如何等待Parallel.ForEach完成

152

我正在使用TPL来进行我的当前项目,并且使用Parallel.ForEach来启动多个线程。Task类包含Wait()方法,以等待任务完成。同样的,我该如何等待Parallel.ForEach完成后再执行下一条语句?

5个回答

232

你不需要做任何特殊的工作,Parallel.Foreach()会等待其所有分支任务完成。从调用线程的角度来看,你可以将其视为单个同步语句,例如,在try/catch语句中包装它。

更新:

旧的Parallel类方法不适合异步(基于Task的)编程。但是,从dotnet 6开始,我们可以使用Parallel.ForEachAsync()

await Parallel.ForEachAsync(items, (item, cancellationToken) =>
  {
     await ... 
  });

有几个可用的重载方法,'body' 方法应该返回一个 ValueTask。


16
"Parallel.ForEach()方法会等待其所有分支任务完成"在某些情况下,可能会令人感到困惑,例如(使用async任务):Parallel.ForEach(groupedUnreadMessages, async unreadMsgCollection => { /works/}); - Bo HU
以下是StackOverflow上的另一个问题:https://dev59.com/aWgu5IYBdhLWcg3wHjl7 - Bo HU
5
这个答案是2011年的,async/await还没有出现。但是像我说的,在ForEach内部生成线程不是一个好主意,也不要使用async Action。你发布的链接提供了很好的信息和解决方案。 - H H
2
在ForEach内生成线程不是一个好主意。你能详细阐述一下吗?除非你确保在返回之前等待。 - Gianthra

20

使用Parallel.Foreach时无需此功能,它仅在可用处理器数量的线程中执行foreach,并返回同步结果。

更多信息可以在这里找到。


10

正如大家所说 - 你不需要等待。根据我的经验,我可以补充一点: 如果你有一个异步体需要执行,并且在其中使用await调用了一些异步方法,它会直接运行我的代码并且不会等待任何东西。因此,我只需将await替换为.Result - 然后它就按预期工作了。但是我不知道这是为什么 :/


最好不要在可以使用异步方法的情况下将其作为同步方法使用。在 Parallel.Foreach 中,我们最好使用 await ... 而不是 .Result - MRebati
@MRebati 我先尝试了在那里使用await,但是代码执行仍然没有等待就运行了...这就是为什么我尝试使用.Result,它以某种方式起作用。但无论如何,也许我做错了其他事情。 - Oleg Boguslawski
1
在我进行了这个更改之后,它对我起作用了。请参考此处的类似解决方案和其他几个解决方案:https://dev59.com/aWgu5IYBdhLWcg3wHjl7#40893434 - Maulik

-1
如果您正在将任务结果存储在列表中,请确保使用诸如ConcurrentBag之类的线程安全数据结构,否则由于并发写入问题可能会导致一些结果丢失。

-3

我相信你可以像下面这样使用IsCompleted:

if(Parallel.ForEach(files, f => ProcessFiles(f)).IsCompleted)
{
    // DO STUFF                
}         

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