C# 嵌套列表的并行填充

C# 嵌套列表的并行填充,c#,parallel-processing,task-parallel-library,C#,Parallel Processing,Task Parallel Library,下面的代码似乎有效——也就是说,用增量整数的子列表填充外部列表 我只是幸运吗 我会小心地预先分配“插槽”,而不是交叉 class Program { static List<List<int>> allLists; static void Main(string[] args) { allLists = new List<List<int>>(553); for (int i = 0; i

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

我只是幸运吗

我会小心地预先分配“插槽”,而不是交叉

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();
    }
}
类程序
{
静态列表所有列表;
静态void Main(字符串[]参数)
{
AllList=新列表(553);
对于(int i=0;i<553;i++)
{
插入(i,new List());
}
可枚举的.Range(0552).AsParallel().ForAll((i)=>InsertRange(i));
}
静态void InsertRange(int索引)
{
allLists[index]=Enumerable.Range(07205.ToList();
}
}

是否存在一个列表将另一个列表丢弃的危险?

根据您可以有一个潜在的非线程安全方法InsertRange(int index)

是的,您应该锁定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;
    }
}
private static Object settingValue=new Object();
静态void InsertRange(int索引)
{
//这一部分可以并行执行。
列表值=可枚举的.Range(07205).ToList();
锁定(设置值)
{
所有列表[索引]=值;
}
}

编辑:您可能很幸运,因为创建列表将花费相当多的时间,而将引用分配给索引号的时间很小。一个分配将完全重叠另一个分配。

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

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

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

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

当然,这一切只有在并行创建内部列表将实际加快代码速度时才有意义,但您必须自己进行测量。

由于
索引
是一个局部变量,我认为它永远不会为每个线程带来多个值,因此是安全的。我必须说,您让我怀疑,但问题也可能在于列表代码本身,它不是原子代码。也许只有当列表需要增长时,你才会面临风险,但你会按照需要的大小启动列表。我所看到的测试它的唯一方法是增加发生冲突的机会,将范围减少到0,1,然后如果所有数据仍然正确,那么您可能是对的…为什么创建所有这些空列表只是为了覆盖它们?为什么要使用
Insert()
而不是
Add()
?最重要的是,如果您想要一个包含固定数量元素的集合,为什么还要使用
List
而不是数组?插入更好,因为即使一个线程以某种方式中断另一个线程,也可能不会导致数据丢失。@MrFox 1。这部分代码是完全同步的,在这一点上没有其他线程。2.并行
Insert()
s无法工作,因为:a<代码>插入()当然不是线程安全的。B您可以在列表中的最后一个位置之后插入(),但不能超过该位置。如果不先预填充外部列表,则子列表之间肯定会出现相互干扰的问题。正如@MrFox所建议的,当列表必须增长时,就会出现问题。我希望它们是列表,因为在填充后,我会对它们使用其他Linq查询。但是您不需要用实际列表填充外部列表,使用
null
s会更好。您也可以对数组使用LINQ查询,因为数组实现了
IEnumerable