2

下面的代码似乎可以工作——也就是说,用增量整数的子列表填充外部列表。

我只是幸运吗?

我很小心预先分配“插槽”而不是交叉。

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();
    }
}

有没有一个清单会毁掉另一个清单的危险?

4

3 回答 3

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;
    }
}

编辑:可能是您很幸运,因为创建列表将花费更多时间,将引用分配给索引号的机会很小,一项分配将与另一项完全重叠。

于 2012-09-06T12:17:27.247 回答
1

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

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

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

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

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

于 2012-09-06T20:46:46.867 回答
0

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

于 2012-09-06T12:09:50.097 回答