2012-09-06 81 views
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(); 
    } 
} 

从来没有危险的一个名单将垃圾另一个?

+0

你为什么要创建所有这些空列表来覆盖它们?你为什么使用'Insert()'而不是'Add()'?最重要的是,如果你想要一个具有固定数量元素的集合,为什么你甚至使用'List'而不是一个数组? – svick

+0

插入方式更好,因为即使一个线程以某种方式中断了另一个线程,它也可能不会导致数据丢失。 – MrFox

+0

@MrFox 1.代码的那部分是完全同步的,在那一点上没有其他线程。 2.并行'Insert()'不会工作,因为:a。 'Insert()'当然不是线程安全的。湾您可以在列表中的最后一个位置后面插入(),但不能超出该位置。 – svick

回答

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

当然,这一切并行创建内部列表实际上将加速你的代码的时候才有意义,但你将不得不衡量的是你自己。

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

编辑:这可能是因为你只是幸运,因为创建列表将花费相当多的时间分配参照索引号的机会很小的一个任务将与另一个完全重叠。

+0

由于'index'是一个局部变量,我认为它绝不会占用每个线程多于一个值,因此是安全的。 – user1200984

+0

我必须说你让我怀疑,但问题也可能在于List代码本身,它不是原子的。也许唯一一次遇到风险的时候,名单需要增长,但是你需要按照规模发起清单。我看到测试它的唯一方法是增加碰撞发生的机会,将范围缩小到0,1然后如果所有数据仍然正确,您可能是正确的... – MrFox