在foreach循环中使用parallel.foreach和task之间的性能差异是什么?

我想知道什么是最好的方法,或者是否有任何文档/文章可以帮助我确定在每个循环的正常情况下使用Parallel.foreach和Task的区别是什么,如下所示:

案例1 – Parallel.foreach:

Parallel.foreach { // Do SOmething thread safe: parsing an xml and then save // into a DB Server thry respoitory approach } 

案例2 – foreach中的任务:

 foreach { Task t1 = Task.factory.startNew(()=> { //Do the same thing as case 1 that is thread safe } } Task.waitall() 
  • 我确实进行了自己的测试,结果显示案例1的表现优于案例2.比例大致如下:顺序vs案例1 vs案例2 = 5s:1s:4s

虽然案例1和案例2几乎有1:4? 那么这是否意味着我们应该始终使用parallel.foreach或parallel.for,如果我们想在循环中并行运行?

首先,关于该主题的最佳文档是CLR的第V部分,通过C#。

http://www.amazon.com/CLR-via-C-Developer-Reference/dp/0735667454/ref=sr_1_1?ie=UTF8&qid=1376239791&sr=8-1&keywords=clr+via+c%23

其次,我希望Parallel.Foreach能够更好地运行,因为它不仅可以创建任务,还可以对它们进行分组。 在Jeffrey Richter的书中,他解释了单独启动的任务将被放在线程池队列中。 锁定实际线程池队列有一些开销。 为了解决这个问题,任务本身有自己的队列来创建它们的任务。 任务持有的这个任务子队列实际上可以在没有锁定的情况下完成一些工作!

我将不得不再次阅读那一章(第27章),所以我不确定Parallel.Foreach是这样工作的,但这是我期望它做的。

他解释说,锁定很昂贵,因为它需要访问内核级别的构造。

在任何一种情况下,都不要指望它们按顺序处理。 由于前面提到的内部原因,使用Parallel.Foreach比foreach关键字更不可能按顺序处理。

Parallel.ForEach()所做的是它创建了少量的Task来处理循环的迭代。 Task相对便宜,但它们不是免费的,所以这往往会提高性能。 循环体快速执行,改进可能非常大。 这是您正在观察的行为的最可能的解释。

你运行了多少个任务? 如果您循环足够,那么创建新任务可能需要大量时间。 即,第一个块在15毫秒内运行,第二个块在1秒内运行,第二个块甚至不运行任务。 取消注释Start ,时间上升到近3秒。 WaitAll只添加少量。

 static class Program { static void Main() { const int max = 3000000; var range = Enumerable.Range(0, max).ToArray(); { var sw = new Stopwatch(); sw.Start(); Parallel.ForEach(range, i => { }); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); } { var tasks = new Task[max]; var sw = new Stopwatch(); sw.Start(); foreach (var i in range) { tasks[i] = new Task(()=> { }); //tasks[i].Start(); } //Task.WaitAll(tasks); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); } } }