Parallel.For和Break()误会?

我正在研究For循环中的Parallelism Break。

阅读本文后 ,我仍然有一个问题:

我希望这段代码:

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:

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

问题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)

PS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

我强烈建议阅读

并行编程模式

(来自微软的免费PDF)

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

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

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

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

Q2:我是对的吗?

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

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

Q3:当我(i == 5)时,我真的打破了怎么样?

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

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