【问题标题】:Parallel.For fail (C#)Parallel.For 失败 (C#)
【发布时间】:2011-06-21 00:49:36
【问题描述】:

我写了一些代码:

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 有什么问题?

【问题讨论】:

    标签: c# parallel-processing


    【解决方案1】:

    您遇到了所谓的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 是最接近线程安全列表的东西。请记住,由于我们正在处理未知的调度,因此整数不会按顺序排列。

    【讨论】:

      【解决方案2】:

      List&lt;&gt; 类不是线程保存。您不能在并行循环中修改它(没有问题)。使用 System.Collections.Concurrent 命名空间中的集合

      【讨论】:

        【解决方案3】:

        List&lt;T&gt; 不是线程安全的类。您应该改用 Concurrent 集合之一或实现自己的同步。

        有关Parallel.For的详细信息,请参阅this answer

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-11
          • 1970-01-01
          • 1970-01-01
          • 2020-04-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多