Finalizer for Parallel.ForEach

匿名 (未验证) 提交于 2019-12-03 02:16:02

问题:

How do I add a finalizer that runs once all parallels have completed?

Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 }, async (entry) =>     // Do something with the entry. });

I have tried like this but it doesn't compile:

Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 }, async (entry) =>     // Do something with the entry. }, () => { // Was hoping this would work. });

回答1:

  1. You should not declare the action for the Parallel.ForEach as async. If you use an await inside that action, the control flow is returned to Parallel.ForEach and its implementation "thinks" that the action is finished. This will lead to a very different behaviour than you expect.

  2. The call to Parallel.ForEach returns when the loop is completed. It returns when all actions have been done for all the elements in the enumeration. So whatever you want to do "when all parallels have completed" can be done right after that call:

    Parallel.ForEach(entries, new ParallelOptions { MaxDegreeOfParallelism = 15 },           (entry) =>          // Do something with the entry. ); DoSomethingWhenAllParallelsHaveCompleted();


回答2:

You dont have to do anything. Your Parallel.ForEach will run until all threads have finished their work. Thats one of the really nice benefits the Parallel.Foreach() has.

So right after Parallel.ForEach(() => { /* code */ }); all threads will be finished.



回答3:

As I and others mentioned in comments Parallel.ForEach does not support async functions the reason is when you did async (entry) => ... that is the same as

Parallel.ForEach(entries, Example);  //elsewhere async void Example(Entry entry) {    ... }

Because the function is async void the ForEach can't tell when a function is "done" so it will just think it is done when you hit the first await instead of when the task finishes.

The way to fix this is to use a library that can suport async functions, TPL Dataflow is a good one. You get it by installing the NuGet package to your project Microsoft.Tpl.Dataflow. You could recreate your previous code as

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


转载请标明出处:Finalizer for Parallel.ForEach
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!