Parallel For Loop - 添加到List时出现问题

时间:2010-05-02 03:39:59

标签: list .net-4.0 c#-4.0 parallel-processing

我遇到一些涉及Parallel for循环并添加到List的问题。问题是,相同的代码可能在不同的时间生成不同的输出。我在下面设置了一些测试代码。在这段代码中,我创建了一个包含10,000个int值的List。 1/10的值将为0,1 / 10的值将为1,一直到值的十分之一为9。

设置此List后,我设置了一个Parallel for循环,遍历列表。如果当前数字为0,我将一个值添加到新列表中。 Parallel for循环完成后,我输出列表的大小。大小应始终为1,000。大多数时候,给出了正确的答案。但是,我已经看到了3种可能的错误结果:

  1. 列表的大小小于1,000
  2. doubleList.Add(0.0);发生IndexOutOfRangeException
  3. doubleList.Add(0.0);发生ArgumentException
  4. 给出的ArgumentException消息是:Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

    可能导致错误的原因是什么?这是一个.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 个答案:

答案 0 :(得分:19)

我希望System.Collections.Generic.List不是线程安全的,这意味着如果你尝试从两个不同的线程同时Add,那么事情就会出错。啊,是的,它在docs中说明了。

您可以通过多种方式防止这种情况发生:

  • 使用允许线程安全添加的集合类型(.Net 4.0中有一些new ones
  • 在添加
  • 之前锁定
  • 为集合使用线程本地存储,并在最后合并它们
  • ...

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