TaskFactory.Tasks中BlockingCollection.GetConsumingEnumerable()集合的Parallel.ForEach和foreach循环

我已经尝试了这两个循环,并注意到即使Task的Action委托中的常规foreach循环应该并行执行,它也不会并行处理元素。 但是,如果我用Parallel.ForEach替换它,我会看到数据正在跨多个线程并行处理。

代码1:

Task loadingTask1 = Factory.StartNew(() => { foreach (MyOneClass dg in Queue.GetConsumingEnumerable()) { MyOtherClass vl = new MyOtherClass(); vl.Id = dg.Id; vl.PerformTimeConsumingAction(); OutputQueue.Add(vl); } }); 

代码2:

 Task loadingTask2 = Factory.StartNew(() => { Parallel.ForEach(Queue.GetConsumingEnumerable(), (dg) => { MyOtherClass vl = new MyOtherClass(); vl.Id = dg.Id; vl.PerformTimeConsumingAction(); OutputQueue.Add(vl); }); }); 

在每次迭代时使用Console.Write语句运行的代码1似乎等待上一个循环完成,直到它抓住下一个循环,但代码2确实并行处理多个元素。

我是否正确理解Task.Action中的常规foreach? 我认为.NET将启动尽可能多的任务线程作为加载保证,并且每个迭代的foreach将被并行处理。

我也尝试将PLINQ结果传递给上述两个代码和观察者相同的行为:常规foreach似乎等待上一次迭代完成以启动下一个代码,即使我使用过.AsParallel().WithExecutionMode(ParallelExecutionMode.ForceParallelism)指令。

任何见解都将受到高度赞赏。 我知道OrderingPartitioner类,可能会尝试使用它

常规foreach 始终按顺序运行迭代。 在某些情况下,没有魔法可以将它变成并行构造。 这就像把你扔进绝望的坑里一样,因为那样就很难断言像foreach循环一样简单的东西的正确性。 幸运的是,C#的目标之一就是让你进入成功的关键:

C#让你陷入成功之中

如果将foreach循环运行在单独的任务上,则会使所有迭代按顺序运行,但您可以与整个foreach并行运行其他代码。

在单独的任务上执行常规foreach的流程如下所示:

  | __v_ / \ other code | | foreach iteration 1 other code | | foreach iteration 2 other code | | foreach iteration 3 ...... other code | | foreach iteration n-1 other code | | foreach iteration n vv 

Parallel.Foreach的执行流程如下所示:

  | _________________v________________ / / / / \ \ \ \ |1 |2 |3 |....| |n-2 |n-1 |n \____\____\____\____/____/____/____/ | v 

希望有助于了解正在发生的事情。