嵌套列表的并行填充

时间:2012-09-06 12:04:58

标签: c# parallel-processing task-parallel-library

下面的代码似乎有效 - 也就是说,使用增量整数的子列表填充外部List。

我只是幸运吗?

我小心翼翼地预先分配“插槽”而不是越过。

class Program
{
    static List<List<int>> allLists;

    static void Main(string[] args)
    {
        allLists = new List<List<int>>(553);

        for (int i = 0; i < 553; i++)
        {
            allLists.Insert(i, new List<int>());
        }

        Enumerable.Range(0, 552).AsParallel().ForAll((i) => InsertRange(i));
    }

    static void InsertRange(int index)
    {
        allLists[index] = Enumerable.Range(0, 7205).ToList();
    }
}

是否存在一个列表会破坏另一个列表的危险?

3 个答案:

答案 0 :(得分:1)

是的,你应该锁定InsertRange方法。但要确保元素的创建仍然是并行完成的:

private static Object settingValue = new Object();
static void InsertRange(int index)
{
    // This part can be executed in parallel.
    List<int> values = Enumerable.Range(0, 7205).ToList();

    lock (settingValue)
    {
        allLists[index] = values;
    }
}

编辑:可能你很幸运,因为创建列表会花费相当多的时间来分配对索引号的引用,一个分配很可能与另一个完全重叠。

答案 1 :(得分:1)

并行访问数组的不同部分在.Net中是线程安全的。由于List<T>由数组支持,我认为您的代码也应该是线程安全的。

但我认为你的事情过于复杂。您可以使用PLINQ生成所有内部列表,然后使用ToArray()创建最终数组(或ToList(),如果您确实要创建List<T>)。由于PLINQ有自己的版本Range()ToArray()(和ToList()),我相信这也会更有效。

所以,我会像这样重写你的代码:

allLists = ParallelEnumerable.Range(0, 552)
    .AsOrdered()
    .Select(i => Enumerable.Range(0, 7205).ToList())
    .ToArray();

当然,只有当并行创建内部列表实际上会加快代码速度时,这一切才有意义,但你必须自己衡量。

答案 2 :(得分:0)

根据Potential pitfalls with PLINQ,您可以使用潜在的非线程安全方法InsertRange(int index)