2010-05-02 71 views
6

我遇到一些涉及Parallel for循环并添加到列表的问题。问题是,相同的代码可能在不同的时间产生不同的输出。我已经在下面设置了一些测试代码。在这段代码中,我创建了一个包含10,000个int值的列表。 1/10的值将为0,1/10的值将为1,一直到1/10的值为9.并行For循环 - 添加到列表时出现问题

设置此列表后,我设置了一个Parallel for循环遍历列表。如果当前的数字是0,我将一个值添加到一个新的列表。 Parallel for循环完成后,我输出列表的大小。尺寸应该始终为1,000。大多数时候,答案都是正确的。然而,我看到3点可能的不正确的结果发生:

  1. 列表的大小小于1,000
  2. 一种IndexOutOfRangeException发生@doubleList.Add(0.0);
  3. 一种ArgumentException发生@doubleList.Add(0.0);

该消息给出的ArgumentException是:Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

什么可能导致错误S'这是.Net错误吗?有什么我可以做,以防止这种情况发生?

请为自己尝试一下。如果您没有收到错误,请尝试几次。另请注意,使用单核机器可能不会看到任何错误。

using System; 
using System.Collections.Generic; 
using System.Threading.Tasks; 

namespace ParallelTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<int> intList = new List<int>(); 
      List<double> doubleList = new List<double>(); 

      for (int i = 0; i < 250; i++) 
      { 
       intList.Clear(); 
       doubleList.Clear(); 

       for (int j = 0; j < 10000; j++) 
       { 
        intList.Add(j % 10); 
       } 

       Parallel.For(0, intList.Count, j => 
       { 
        if (intList[j] == 0) 
        { 
         doubleList.Add(0.0); 
        } 
       }); 

       if (doubleList.Count != 1000) 
       { 
        Console.WriteLine("On iteration " + i + ": List size = " + doubleList.Count); 
       } 
      } 

      Console.WriteLine("\nPress any key to exit."); 
      Console.ReadKey(); 
     } 
    } 
} 
+1

什么更可能是.NET错误或代码中的错误? – 2010-05-02 03:50:30

+0

调试规则1:错误总是在你的代码中。你可以从* title *这个... – Aaronaught 2010-05-02 03:58:20

回答

18

我希望System.Collections.Generic.List是不是线程安全的,也就是说如果你试图从两个不同的线程同时Add,事情会出问题。啊,是的,它在docs中这么说。

你可以防止这种情况在许多方面发生了:

  • 使用集合类型,允许线程增加(有一些new ones在.NET 4.0中)
  • 锁添加之前
  • 使用线程本地存储的集合,并在年底
  • 将它们合并...

这些是数据并行代码遇到的非常典型的问题。

+1

+1中判断出了什么问题。 System.Collections.Generic.List不是线程安全的。 .NET Framework 4.0中的线程安全集合 – 2010-05-02 03:51:28

+0

+1对于您的第三个建议可能比其他两个建议快得多。 – tster 2010-05-02 03:54:03

+0

@tster - 是的,甚至有一个Parallel.For超载,以帮助该策略:http://msdn.microsoft.com/en-us/library/dd783586.aspx – Brian 2010-05-02 03:57:12