10

我正在调查 For 循环中的并行中断。

读完这个这个后, 我还有一个问题:

我希望这段代码:

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

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

02351486
013542
0135642

很烦人。(Break() {after 5} 到底在哪里??)

所以我看了一下msdn

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

Quesion #1 :

哪些迭代?整体迭代计数器?还是每个线程?我很确定它是每个线程。请批准。

Question #2 :

假设我们正在使用 Parallel + range 分区(由于元素之间没有 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 个元素的原因吗?

Question #3 :

我怎么真的破了(i == 5)

ps

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

4

3 回答 3

10

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

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

发生的情况是,当您遇到索引为 5 的循环时,您会发送“中断”请求。 Break()将导致循环不再处理任何值>5,而是处理所有值<5

但是,任何大于 5 且已启动的值仍将得到处理。由于各种索引是并行运行的,因此它们不再是有序的,因此您会得到各种运行,其中某些值>5(例如您的示例中的 8)仍在执行。

哪些迭代?整体迭代计数器?还是每个线程?我很确定它是每个线程。请批准。

这是传递给 Parallel.For 的索引。Break() 不会阻止处理项目,但可以保证处理最多 100 的所有项目,但超过 100 的项目可能会或可能不会被处理。

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

是的。如果您使用所示的分区器,一旦您调用Break(),超出您中断的项目将不再被安排。但是,已经安排好的项目(即整个分区)将得到完全处理。在您的示例中,这意味着您可能总是处理所有 1000 个项目。

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

你是 - 但是当你并行运行时,事情就会改变。这里的实际目标是什么?如果您只想处理前 6 个项目 (0-5),则应在通过 LINQ 查询或类似查询循环遍历它们之前限制这些项目。然后,您可以处理 6 项Parallel.ForParallel.ForEach不使用 aBreak()且无需担心。

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

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

于 2012-10-08T15:17:12.433 回答
6

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

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

您的线程可以并且将以不确定的顺序运行。当遇到 .Break() 指令时,将不再开始循环迭代。究竟何时发生取决于特定运行的线程调度的细节。

我强烈推荐阅读

并行编程模式

(Microsoft 提供的免费 PDF)

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

于 2012-10-08T15:16:58.773 回答
4

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

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

请记住,委托可能会出现故障,无法保证迭代i == 5将是第六次执行,除非在极少数情况下,否则这种情况不太可能发生。

Q2:我说的对吗?

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

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

Q3:当 (i == 5) 时,我如何真正打破?

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

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

于 2012-10-08T15:21:55.903 回答