停止与并行中断。对

时间:2013-04-28 09:53:14

标签: c# .net loops task-parallel-library

我很难理解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个数字。

任何人都可以提供帮助?

P.S。我有i5 520M CPU(2核= 4线程)

7 个答案:

答案 0 :(得分:11)

loopState.Break()不会像return那样破坏函数。因此,loopState.Break()之后的行仍将执行。在该范围的该范围结束后,for会检查是否已调用loopState.Break()。如果是这样,则允许所有循环继续,直到达到名为Break的数字。

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

循环50..74和75..99甚至不会开始,因为第二个循环25..49已经中止了整个for-operation,因为它们的数据大于破碎数10。

答案 1 :(得分:3)

来自the documentation of Break()

  

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

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

答案 2 :(得分:2)

if (i >= 10) loopState.Break();仍会继续当前的迭代。因此打印10

但是,调用loopState.Break()后的迭代次数(i> = 10)将无法启动。

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

第一个帖子有:0-24。
第二个帖子有:25 - 49 第3个帖子有:50 - 74 第4个帖子有:75 - 99.

根据我的理解,每个线程都会循环数字本身。根据{{​​3}},它说

  

如果在调用Break时已经启动了其他迭代,则可以运行。

由于第二个线程几乎与第一个线程同时启动,因此打印0, 25。然后在第二个帖子中循环if (i >= 10) loopState.Break();时调用25

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

图片参考:this post

答案 3 :(得分:1)

中断可确保完成当前正在运行的所有迭代。

停止只会终止所有内容。

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:1)

最简单的答案:

停止和中断都会阻止新的迭代开始。两者都确保开始迭代完成。

差异 - 停止 - 中止它所调用的迭代并中断不会。

答案 6 :(得分: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')); 
    }
});   

enter image description here

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

如果您确实想尽快终止循环,而不必担心要保证所有先前的迭代 完成后,ParallelLoopState还有另一个名为 Stop()的方法。 Stop方法尝试结束 尽快循环-发出后,没有循环任务将开始新的迭代