如何在所有并行完成后添加运行的终结器?
Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 }, async (entry) =>
// Do something with the entry.
});
我试过这样但是没有编译:
Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 }, async (entry) =>
// Do something with the entry.
}, () => { // Was hoping this would work. });
答案 0 :(得分:3)
您应不将Parallel.ForEach
的操作声明为async
。如果在该操作中使用await
,则控制流将返回到Parallel.ForEach
,并且其实现"认为"该操作已完成。这将导致与您期望的不同的行为。
对Parallel.ForEach
的调用在循环完成时返回 。它在枚举中的所有元素都已完成所有操作后返回。所以无论你想做什么"当所有的并行完成时#34;可以在电话会议后立即完成:
Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 },
(entry) =>
// Do something with the entry.
);
DoSomethingWhenAllParallelsHaveCompleted();
答案 1 :(得分:1)
你不必做任何事情。您的Parallel.ForEach
将一直运行,直到所有线程完成其工作。这是Parallel.Foreach()
带来的非常好的好处之一。
所以Parallel.ForEach(() => { /* code */ });
之后所有线程都将完成。
答案 2 :(得分:1)
正如我和其他人在评论Parallel.ForEach
中提到的不支持异步函数一样,原因是当你async (entry) => ...
与
Parallel.ForEach(entries, Example);
//elsewhere
async void Example(Entry entry)
{
...
}
因为函数是async void
,ForEach
无法告诉函数何时完成"所以当你点击第一个await
而不是任务完成时,它会认为它已经完成。
解决这个问题的方法是使用一个可以支持异步函数的库,TPL Dataflow是一个很好的函数。您可以通过将NuGet包安装到项目Microsoft.Tpl.Dataflow
来获得它。您可以将以前的代码重新创建为
private const int MAX_PARALLELISM = 15
public async Task ProcessEntries(IEnumerable<Entry> entries)
{
var block = new ActionBlock<Entry>(async (entry) =>
{
//This is now a "async Task" instead of a async void
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = MAX_PARALLELISM
});
foreach(var entry in entries)
{
await block.SendAsync(entry);
}
block.Complete();
await block.Completion;
DoExtraWorkWhenDone();
}