平行的.Foreach c#暂停和停止函数
本文关键字:函数 暂停 Foreach | 更新日期: 2023-09-27 18:17:23
暂停和停止(在它结束之前)parallel.foreach最有效的方法是什么?
Parallel.ForEach(list, (item) =>
{
doStuff(item);
});
damien_the_unbelieve有一个很好的方法,但这只是当你想让一些外部进程停止循环。如果你想让循环像在正常的for
或foreach
循环中使用break
一样爆发,你将需要使用一个具有ParallelLoopState
作为循环体参数之一的过载。ParallelLoopState
有两个功能,Stop()
和Break()
与你想做的事情相关。
函数Stop()
将在系统最方便的时候停止处理元素,这意味着在调用stop()之后可以执行更多的迭代,并且不能保证在您停止的元素之前出现的元素甚至已经开始处理。
函数Break()
的执行与Stop()
完全相同,但是它也将计算IEnumerable
中位于您调用Break()
的项目之前的所有元素。当您不关心元素的处理顺序,但必须处理所有元素直到您停止的点时,这是有用的。
检查从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:线程20、假,下一个继续。3、假,下一个继续1、假,继续下一个4、真,中断2、正确,打破5、不要处理打破之前现在被调用的最低索引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:线程20、假,下一个继续。3、假,下一个继续1、假,下一步继续。4、真,停止2、不加工,停止之前在本例中,它将返回4作为答案。让我们看看同样的过程,但如果它处理所有其他元素,而不是0-2和3-5。
<>之前线程1:线程20,假,下一个继续1,假,下一个继续2、为真,停止。3、为假,下一步继续4、不加工,停止之前这次它将返回2而不是4。
为了能够停止Parallel.ForEach
,您可以使用接受ParallelOptions
参数的重载之一,并在这些选项中包含CancellationToken
。
详情请参见取消。
至于暂停,我不明白你为什么要这样做。您可能正在寻找一个Barrier(用于协调多个线程之间的努力,例如如果它们都需要在继续进行B部分之前完成a部分),但我不认为您会使用Parallel.ForEach
,因为您不知道将有多少参与者。