17

我很难理解loopState.Stop()loopState.Break()。我已经阅读了 MSDN 和几篇关于它的帖子,但我仍然感到困惑。

我的理解是,每个迭代分区器都会为线程提供剩余的索引来处理并loopState.Stop()停止所有线程并loopState.Break()停止当前线程。

但是,让我们考虑以下情况:

Parallel.For(0, 100, (i, loopState) =>
{
    if (i >= 10) 
        loopState.Break();
    Debug.Write(i);
});

对于这个循环,我有以下结果:

0 25 1 2 3 4 5 6 7 8 9 10 

我不知道为什么结果中有 10 个和 25 个数字。

任何人都可以帮忙吗?

PS我有i5 520M CPU(2核=> 4线程)

4

7 回答 7

12

loopState.Break()不会像return. 所以后面的行loopState.Break()仍然会被执行。在该号码的范围结束后,for检查是否loopState.Break()已调用。如果是这样,则允许所有循环继续,直到达到被调用的数量Break

在您的示例中,从 0 到 24 的循环将与从 25 到 49 的循环同时中断(并显示它们的“中断”数字)。

循环 50..74 和 75..99 甚至都不会开始,因为第二个循环 25..49 已经中止了整个 for 操作,因为它们的起始编号大于中断编号 10。

于 2013-04-28T10:18:49.583 回答
5

以下文档Break()

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

这意味着当前迭代仍将完成(因此10被打印)。Break()也无法进行时间旅行,因此25将保持打印状态。这Break()意味着不会开始任何新的迭代10

于 2013-04-28T11:11:31.823 回答
4

最简单的答案:

stop 和 break 都阻止新的迭代开始。两者都确保开始迭代完成。

差异 - 停止 - 中止它调用的迭代,而 break 不会。

于 2018-05-22T14:42:39.343 回答
4

if (i >= 10) loopState.Break();仍将继续当前迭代。如此10印制。

但是,被调用之后的迭代(i >= 10)loopState.Break()将不会开始。

但是为什么25要打印呢?下图将解释原因。由于您有 4 个线程,因此 0-99 将被划分为 4。

第一个线程有:0-24。
第 2 线程有:25 - 49。
第 3 线程有:50 - 74。
第 4 线程有:75 - 99。

根据我的理解,每个线程都会自己循环数字。根据这篇文章,它说

如果在调用 Break 时它们已经开始,则可以运行其他迭代。

由于第 2 个线程与第 1 个线程几乎同时开始,所以0, 25打印出来。然后在第二个线程中if (i >= 10) loopState.Break();循环时调用。25

第 3 和第 4 线程中的循环在调用之前没有开始,Break()因此任何大于10未打印的数字。

图片参考:http ://www.albahari.com/threading/part5.aspx

于 2017-09-20T02:11:14.640 回答
2

静态Parallel类的所有方法都返回ParallelLoopResult。这个对象有两个属性 -IsCompletedLowestBreakIteration

当我们使用 时loopState.Break()LowestBreakIteration返回一个整数,表示调用 Break 语句的最低迭代次数

当我们使用loopState.Stop()时,LowestBreakIteration返回null

于 2018-02-17T11:07:34.587 回答
1

Break确保当前正在运行的所有迭代都将完成。

停止只是终止一切。

于 2017-01-21T11:51:45.657 回答
0
void Log(string prefix, bool isBreak=false) 
{
    var msg = isBreak ? " Break" : "";
    Console.WriteLine($"{prefix} task: {Task.CurrentId.ToString().PadLeft(3,'0')} {msg}");

}
long lockFlag=0;
Parallel.For(0, 130, (i, loopState) =>
{
    if (i >= 10 && Interlocked.Read(ref lockFlag)==0)
    {
        lockFlag=Interlocked.Increment(ref lockFlag);
        loopState.Break();
        //Statement after break will still execute for current iteration
        Log(i.ToString().PadLeft(3,'0'),true);
    }
    else
    {
      Log(i.ToString().PadLeft(3,'0')); 
    }
});   

在此处输入图像描述

任务“8904”继续运行以完成小于 25 的所有迭代。显然,如果表示值大于 25 的迭代已经完成,那么将无法回滚。

如果您确实想尽快终止循环并且不关心保证所有先前的迭代都已完成,那么 ParallelLoopState 有另一个称为Stop()的方法。Stop 方法试图尽快结束循环——一旦发出,循环任务将不会开始新的迭代

于 2018-12-06T20:28:45.517 回答