Parallel.For和Break()误会?

时间:2012-10-08 15:14:48

标签: c# .net .net-4.0 parallel-processing task-parallel-library

我正在调查For循环中的Parallelism Break。

在阅读this this之后,我仍然有一个问题:

我希望这段代码:

 Parallel.For(0, 10, (i,state) =>  
     { 
                Console.WriteLine(i); if (i == 5) state.Break(); 
     }

大多数 6个数字(0..6)产生。 他不仅没有这样做,而且结果长度不同:

02351486
013542
0135642

非常讨厌。 (那里的地狱是Break(){5之后}这里??)

所以我看了msdn

  

Break可以用于与循环通信,在当前迭代之后不需要运行其他迭代。   如果从迭代的for循环的第100次迭代中调用Break   并行从0到1000,所有小于100的迭代仍然应该   运行,但不需要从101到1000的迭代。

问题#1:

哪些迭代?整个迭代计数器?还是每个帖子?我很确定这是每个帖子。请批准。

问题#2:

让我们假设我们正在使用并行+范围分区(由于元素之间没有cpu成本变化),因此它在线程之间划分数据。因此,如果我们有4个核心(并且它们之间有完美的划分):

core #1 got 0..250
core #2 got 251..500
core #3 got 501..750
core #4 got 751..1000

所以core #1中的帖子有时会遇到value=100并且会中断。 这将是他的迭代号100。 但是core #4中的线程得到了更多的量子,他现在在900。他超越他的100'th次迭代。 他没有指数少于100被停止!! - 所以他会全部展示。

我是对的吗?这就是我在我的例子中获得超过5个元素的原因吗?

问题#3:

(i == 5)时我真正打破了什么?

P.S。

我的意思是,来吧!当我做Break()时,我希望循环停止。 正如我在常规For循环中所做的那样。

3 个答案:

答案 0 :(得分:10)

  

最多产生6个数字(0..6)。

问题是这不会最多产生6个数字

当您点击索引为5的循环时,会发送“中断”请求。 Break()会导致循环不再处理任何值>5,但会处理所有值<5

但是,任何已经启动的大于5的值仍将被处理。由于各个索引并行运行,因此它们不再被排序,因此您可以进行各种运行,其中某些值>5(例如示例中的8)仍在执行。

  

哪些迭代?整个迭代计数器?还是每个帖子?我很确定这是每个帖子。请批准。

这是传递给Parallel.For的索引。 Break()不会阻止项目被处理,但可以保证最多100个项目得到处理,但100以上的项目可能会被处理,也可能不会被处理。

  

我是对的吗?这就是我在我的例子中获得超过5个元素的原因吗?

是。如果你使用的是像你所示的分区程序,只要你拨打Break(),你破坏的项目之外的项目将不再安排。但是,已经安排的项目(整个分区)将被完全处理。在您的示例中,这意味着您可能始终处理所有1000个项目。

  

我怎样才能真正打破(i == 5)?

你是 - 但是当你并行运行时,事情会发生变化。这里的实际目标是什么?如果您只想处理前6项(0-5),则应通过LINQ查询或类似方法限制之前的项。然后,您可以Parallel.ForParallel.ForEach处理6个项目而无需Break(),无需担心。

  

我的意思是,来吧!当我做Break()时,我希望循环停止。正如我在常规For循环中所做的那样。

如果您希望尽快停止播放,则应使用Stop()代替Break()。这不会阻止已经运行的项目停止,但不会再安排任何项目(包括枚举中较低索引或更早的项目,而不是当前位置)。

答案 1 :(得分:6)

  

如果从for循环的第100次迭代调用Break,则从0到1000并行迭代

循环的第100次迭代不一定(实际上可能不是)索引为99的那个。

您的主题可以并且将以不确定的顺序运行。遇到.Break()指令时,不会再启动循环迭代。究竟何时发生这种情况取决于特定运行的线程调度的具体情况。

我强烈建议您阅读

Patterns of Parallel Programming

(来自Microsoft的免费PDF)

了解进入TPL的设计决策和设计权衡。

答案 2 :(得分:4)

  

哪些迭代?整个迭代计数器?还是按线程?

关闭所有已安排(或尚未安排)的迭代。

请记住,委托可能无序运行,无法保证迭代i == 5将是第六个执行,除非在极少数情况下这种情况不太可能。

  

Q2:我是对的吗?

不,调度不是那么简单。而是将所有任务排队,然后处理队列。但是每个线程都使用自己的队列,直到它们从其他线程中窃取时为空。这导致无法预测哪个线程将处理代理。

如果委托是非常简单的,那么它可能都会在原始调用线程上处理(没有其他线程有机会窃取工作)。

  

问题3:当我(i == 5)时,我真正打破了什么?

如果您想要线性(特定)处理,请不要同时使用。

Break方法用于支持推测性执行:尝试各种方法,并在任何人完成后立即停止。