Parallel.Foreach c#暂停和停止function?

什么是最有效的暂停和停止(在它结束之前)parallel.foreach的方法?

Parallel.ForEach(list, (item) => { doStuff(item); }); 

Damien_The_Unbeliver有一个很好的方法,但只有你想让一些外部进程停止循环。 如果你想让循环中断,就像在普通forforeach循环中使用break ,你需要使用一个带有ParallelLoopState 的重载作为循环体的参数之一。 ParallelLoopState有两个与你想要做的事情相关的函数, Stop()Break()

函数Stop()在系统最早的方便时停止处理元素这意味着在调用Stop()之后可以执行更多迭代,并且不能保证在您停止的元素之前的元素甚至已经开始处理。

函数Break()执行与Stop()完全相同,但它也将评估在您调用Break()之前的项目之前的IEnumerable所有元素。 当您不关心处理元素的顺序时,这非常有用,但您必须处理所有元素,直到您停止的点为止。

检查foreach返回的ParallelLoopResult以查看foreach是否提前停止,如果使用了Break() ,它处理的编号最小的项目是什么。

 Parallel.ForEach(list, (item, loopState) => { bool endEarly = doStuff(item); if(endEarly) { loopState.Break(); } } ); //Equivalent to the following non parallel version, except that if doStuff ends early // it may or may not processed some items in the list after the break. foreach(var item in list) { bool endEarly = doStuff(item); if(endEarly) { break; } } 

这是一个更实际的例子

 static bool[] list = new int[]{false, false, true, false, true, false}; long LowestElementTrue() { ParallelLoopResult result = Parallel.ForEach(list, (element, loopState) => { if(element) loopState.Break(); } if(result.LowestBreakIteration.IsNull) return -1; else return result.LowestBreakIteration.Value; } 

无论它如何分割工作,它总是返回2作为答案。

假设处理器调度两个线程来处理它,第一个线程处理元素0-2,第二个线程处理元素3-5。

线程1:线程2
 0,错误,继续下3,假,继续下一步
 1,假,继续下4,真,rest
 2,True,Break 5,不要处理Broke

现在最低的索引Break是从2调用的,所以ParallelLoopResult.LowestBreakIteration每次都会返回2,无论线程是如何分解的,因为它总是会处理到数字2。

这里有一个如何使用Stop的例子。

 static bool[] list = new int[]{false, false, true, false, true, false}; long FirstElementFoundTrue() { long currentIndex = -1; ParallelLoopResult result = Parallel.ForEach(list, (element, loopState, index) => { if(element) { loopState.Stop(); //index is a 64 bit number, to make it a atomic write // on 32 bit machines you must either: // 1. Target 64 bit only and not allow 32 bit machines. // 2. Cast the number to 32 bit. // 3. Use one of the Interlocked methods. Interlocked.Exchange (ref currentIndex , index); } } return currentIndex; } 

根据它如何分割工作,它将返回2或4作为答案。

假设处理器调度两个线程来处理它,第一个线程处理元素0-2,第二个线程处理元素3-5。

线程1:线程2
 0,错误,继续下3,假,继续下一步
 1,假,继续下4,真,停
 2,不处理,停止5,不处理,停止

在这种情况下,它将返回4作为答案。 让我们看看相同的过程,但如果它处理所有其他元素而不是0-2和3-5。

线程1:线程2
 0,False,接下来1,False,继续下一步
 2,True,Stop 3,False,接下来继续
 4,不处理,停止5,不处理,停止

这次它将返回2而不是4。

为了能够停止Parallel.ForEach ,您可以使用其中一个接受ParallelOptions参数的重载,并在这些选项中包含CancellationToken

有关更多详细信息,请参阅取消

至于暂停 ,一般来说,我想不出你为什么要那样做。 您可能正在寻找一个障碍 (用于协调多个线程之间的工作,比如他们都需要在继续参加B之前完成A部分),但我不认为您将它与Parallel.ForEach ,因为你不知道会有多少参与者。