打破parallel.foreach?

132

如何跳出一个parallel.for循环?

我有一条相当复杂的语句,如下所示:

Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),
    new Action<ColorIndexHolder>((ColorIndexHolder Element) =>
    {
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I)
        {
            Found = true;
            break;
        }
    }));

使用并行类,我可以大幅度优化这个进程。然而,我无法找出如何打破并行循环?break;语句会抛出以下语法错误:

没有封闭的循环可以中断或继续


1
你是否期望循环的所有并行实例同时中断? - n8wrl
5个回答

211

使用ParallelLoopState.Break方法:

 Parallel.ForEach(list,
    (i, state) =>
    {
       state.Break();
    });

根据你的情况:

Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),
    new Action<ColorIndexHolder, ParallelLoopState>((ColorIndexHolder Element, ParallelLoopState state) =>
    {
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I)
        {
            Found = true;
            state.Break();
        }
    }));

1
考虑到一个顺序的 foreach 循环,可以保证在导致跳出循环的某个项目之前的所有项目都会被处理。那么对于 Parallel.ForEach 呢,其中项目的顺序不一定是它们被处理的顺序,是否也能保证 IEnumerable<...> 中在调用 state.Break() 方法之前的所有项目都被处理了,其后的项目则没有被处理?虽然前者可以以某种方式实现,但我不知道后者如何可能。 - Hendrik Wiese
6
文档中写道:“调用Break方法会通知for循环,在当前迭代之后的迭代不必执行。但是,如果之前的迭代尚未执行,则所有之前的迭代仍然必须被执行。”另外,“不能保证在当前迭代之后的迭代一定不会执行。” - Tudor
2
那么,正如Mike Perrenoud和MBentley所提到的那样,state.Stop()是否更适合可靠地实现预期结果? - xtreampb
有没有比“state”更直观的变量名呢? - Kellen Stuart

54

3
+1,看起来我们这里有几个人的答案完全相同 :) -- 哦,对了,在那个评论上我支持你。 - Mike Perrenoud
谢谢你的解释。你知道当 break 或 stop 被调用时,当前正在执行的迭代是否会被完成,还是会在执行中途停止迭代吗? - CeejeeB
1
@CeejeeB 当前正在执行的操作已完成。 - Reed Copsey

19

LoopState肯定是一个很好的答案。我发现之前的答案有很多其他的东西,让人很难看到答案,所以这里给出一个简单的例子:

using System.Threading.Tasks;

Parallel.ForEach(SomeTable.Rows(), (row, loopState) =>
{
    if (row.Value == testValue)
    {
        loopState.Stop();  // Stop the ForEach!
    }       
    // else do some other stuff here.
});

12

你应该使用 Any,而不是使用 for 循环:

bool Found = ColorIndex.AsEnumerable().AsParallel()
    .Any(Element => Element.StartIndex <= I 
      && Element.StartIndex + Element.Length >= I);

Any 足够聪明,一旦知道结果必须为true就会停止。


真的。但是,如果您必须在迭代内执行某种其他查找或逻辑,则“Any”将无法工作。 - dst3p
@dst3p 你为什么认为这不会起作用?当然,如果你在其他数据结构中查找某些内容或执行其他复杂逻辑时,你需要确保在多线程环境下是安全的,但有很多方法可以做到这两件事情是安全的。你为什么认为你不能在这里查找任何内容或执行任何逻辑呢? - Servy
你说得对,我已经在Java的世界里生活了太久。 - dst3p

5
只需使用可以提供的loopState
Parallel.ForEach<ColorIndexHolder>(ColorIndex.AsEnumerable(),  
    new Action<ColorIndexHolder>((Element, loopState) => { 
        if (Element.StartIndex <= I && Element.StartIndex + Element.Length >= I) { 
            loopState.Stop();
        }     
})); 

请看这个MSDN文章,里面有一个例子。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接