并行。失败(C#)

时间:2011-06-18 13:14:17

标签: c# parallel-processing

我写了一些代码:

class Program
    {
        public const int count = 3000;
        static List<int> list = new List<int>();
        static void DoWork(int i)
        {            
            list.Add(i);
        }        
        static void Main(string[] args)
        {
            while (true)
            {

                Stopwatch s = new Stopwatch();
                s.Start();
                Parallel.For(0, count + 1, DoWork);            
                s.Stop();
                Console.WriteLine("\n Elapsed: " + s.Elapsed.ToString());
                Console.WriteLine("Expected: {0}", count + 1);
                Console.WriteLine("count: {0}", list.Count);
                Console.ReadKey();
                list = new List<int>(); 
            }
        }
    }

但不期望结果(

在Console.WriteLine调用

之前,并非所有周期都已完成

使用Parallel.For有什么问题?

3 个答案:

答案 0 :(得分:7)

你正在遇到所谓的Race Condition。由于.Net中的List集合不是线程安全的,因此Add()之类的操作不是原子的。基本上,在一个线程上调用Add()可以在完成之前销毁另一个线程的Add()。您的代码需要一个线程安全的并发集合。

试试这个:

using System.Threading.Tasks;
class Program
{

    public const int count = 3000;
    static ConcurrentBag<int> bag = new ConcurrentBag<int>();
    static void DoWork(int i)
    {
        bag.Add(i);
    }
    static void Main(string[] args)
    {
        while (true)
        {

            Stopwatch s = new Stopwatch();
            s.Start();
            Parallel.For(0, count + 1, DoWork);
            s.Stop();
            Console.WriteLine("\n Elapsed: " + s.Elapsed.ToString());
            Console.WriteLine("Expected: {0}", count + 1);
            Console.WriteLine("count: {0}", bag.Count);
            Console.ReadKey();
            bag = new ConcurrentBag<int>();
        }
    }
}

ConcurrentBag是最接近线程安全列表的东西。请记住,因为我们正在处理未知的调度,所以整数将不按顺序排列。

答案 1 :(得分:1)

List<>类不是线程保存。您无法在并行循环中修改它(没有问题)。使用System.Collections.Concurrent命名空间

的集合

答案 2 :(得分:1)

List<T>不是线程安全的类。您应该使用其中一个Concurrent集合,或者实现自己的同步。

有关Parallel.For

的详细信息,请参阅this answer