Parallel.ForEach的终结器

时间:2016-06-22 16:23:58

标签: c# .net multithreading

如何在所有并行完成后添加运行的终结器?

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. });

3 个答案:

答案 0 :(得分:3)

  1. 您应Parallel.ForEach的操作声明为async。如果在该操作中使用await,则控制流将返回到Parallel.ForEach,并且其实现"认为"该操作已完成。这将导致与您期望的不同的行为

  2. 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 voidForEach无法告诉函数何时完成"所以当你点击第一个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();
}