TaskFactory.Tasks 中 BlockingCollection.GetConsumingEnumerable() 集合的 Parallel.ForEach 和 foreach 循环
我对这两个循环进行了实验,并注意到即使任务的 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 类并可以尝试使用它
I have experimented with both of these loops and came to notice that even though regular foreach loop in Task's Action delegate supposed to perform in parallel, it doesn't process elements in parallel. However if i replace it with Parallel.ForEach i see data is being processed in parallel across multiple threads.
Code 1:
Task loadingTask1 = Factory.StartNew(() =>
{
foreach (MyOneClass dg in Queue.GetConsumingEnumerable())
{
MyOtherClass vl = new MyOtherClass();
vl.Id = dg.Id;
vl.PerformTimeConsumingAction();
OutputQueue.Add(vl);
}
});
Code 2:
Task loadingTask2 = Factory.StartNew(() =>
{
Parallel.ForEach(Queue.GetConsumingEnumerable(), (dg) =>
{
MyOtherClass vl = new MyOtherClass();
vl.Id = dg.Id;
vl.PerformTimeConsumingAction();
OutputQueue.Add(vl);
});
});
Code 1 when run with Console.Write statement on each iteration seems to be waiting for the previous cycle to complete till it grabs next one, but Code 2 does process multiple elements in parallel.
Am i not understanding regular foreach in Task.Action correctly? I thought .NET would start as many threads for the task as load warrants and each iteration of foreach would be processed in parallel.
I have also tried passing PLINQ result to both of the above codes and observer same behavior: regular foreach seemed to wait for the previous iteration to complete to start the next one, even though i have used .AsParallel()
and .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
directives.
Any insight would be highly appreciated.
I am aware of OrderingPartitioner class and may try using it
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
常规的 foreach 总是按顺序运行其迭代。在某些情况下,没有什么魔法可以将其变成并行结构。这就像把你扔进 坑绝望,因为这样就很难断言像 foreach 循环这样简单的东西的正确性。幸运的是,C# 的目标之一就是把你扔进成功的深渊:
任务上,则所有迭代都会按顺序运行,但您可以与整个 foreach 并行运行其他代码。
在单独的任务上执行常规 foreach 的流程如下所示:
Parallel.Foreach
的执行流程如下所示:希望有助于理解正在发生的情况。
A regular foreach always runs its iterations sequentially. There is no magic that turns it into a parallel construct in some situations. That would be like throwing you into the pit of despair, because then it would be difficult to assert the correctness of something as simple as a foreach loop. Fortunately, one of the goals of C# is to throw you into the pit of success:
If you put a foreach loop running on a separate task, you get all the iterations running sequentially, but you can run other code in parallel with the entire foreach.
The flow of execution of a regular foreach on a separate task looks like this:
And the flow of execution of a
Parallel.Foreach
looks like this:Hope that helps understand what's happening.