我已经尝试了这两个循环,并注意到即使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()
和{ {1}}指令。
任何见解都将受到高度赞赏。 我知道OrderingPartitioner类,可能会尝试使用它
答案 0 :(得分:18)
常规foreach 始终按顺序运行其迭代。在某些情况下,没有魔法可以将它变成并行构造。这就像把你扔进pit of despair,因为那样就很难断言像foreach循环一样简单的东西的正确性。幸运的是,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
v v
Parallel.Foreach
的执行流程如下:
|
_________________v________________
/ / / / \ \ \ \
|1 |2 |3 |....| |n-2 |n-1 |n
\____\____\____\____/____/____/____/
|
v
希望有助于了解正在发生的事情。