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

Kev*_*ell 6 parallel-processing list .net-4.0 c#-4.0

我有一些涉及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. 发生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.

可能导致错误的原因是什么?这是一个.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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 19

我希望System.Collections.Generic.List不是线程安全的,这意味着如果你尝试Add从两个不同的线程并发,事情就会出错.啊,是的,它在文档中也是如此.

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

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

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

  • @Aaronaught,我很确定这只是凯文玩平行的一个例子.我怀疑他是否真的需要为他随机生成的数组中的每个元素的列表添加一个值,该值为0. (2认同)