149

I'm using TPL in my current project and using Parallel.Foreach to spin many threads. The Task class contains Wait() to wait till the task gets completed. Like that, how I can wait for the Parallel.ForEach to complete and then go into executing next statements?

Ardalan Shahgholi
  • 11,967
  • 21
  • 108
  • 144
VJAI
  • 32,167
  • 23
  • 102
  • 164

5 Answers5

230

You don't have to do anything special, Parallel.Foreach() will wait until all its branched tasks are complete. From the calling thread you can treat it as a single synchronous statement and for instance wrap it inside a try/catch.

Update:

The old Parallel class methods are not a good fit for async (Task based) programming. But starting with dotnet 6 we can use Parallel.ForEachAsync()

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

There are a few overloads available and the 'body' method should return a ValueTask.

H H
  • 263,252
  • 30
  • 330
  • 514
  • 16
    "Parallel.Foreach() will wait until all its branched tasks are complete" it can be confused in some situation, like (async task inside): Parallel.ForEach(groupedUnreadMessages, async unreadMsgCollection => { /*works*/}); – Bo HU Jul 27 '16 at 10:41
  • here is an other issues in stackoverflow : http://stackoverflow.com/questions/11564506/nesting-await-in-parallell-foreach – Bo HU Jul 27 '16 at 10:47
  • 5
    This answer is from 2011, before async/await. But like I said, spawning threads inside the ForEach isn't a good idea. Neither is an async Action. The links you posted provides good info and solutions. – H H Jul 27 '16 at 11:23
  • 2
    "spawning threads inside the ForEach isn't a good idea" can you expand? Is that "unless you make sure you await before returning"? – Gianthra Jun 28 '18 at 09:11
20

You don't need that with Parallel.Foreach: it only executes the foreach in as many thread as there are processors available, but it returns synchronously.

More information can be found here

Louis Kottmann
  • 16,268
  • 4
  • 64
  • 88
10

As everyone here said - you dont need to wait for it. What I can add from my experience: If you have an async body to execute and you await some async calls inside, it just ran through my code and did not wait for anything. So I just replaced the await with .Result - then it worked as intended. I couldnt find out though why is that so :/

  • it's better not to use async methods as sync when you can do the first mode. in `Parallel.Foreach` we better use the `await ...` instead of `.Result` on them. – MRebati Sep 01 '20 at 13:06
  • @MRebati I tried first the await in there, but the code execution ran nonetheless through without awaiting... Thats why I tried .Result and it worked somehow. But whatever, maybe I did something else wrong – Oleg Boguslawski Sep 02 '20 at 18:13
  • 1
    It worked for me after this change, refer similar and few other solutions here: https://stackoverflow.com/a/40893434/12193988 – Maulik Nov 16 '21 at 04:58
-1

if you are storing results from the tasks in a List, make sure to use a thread-safe data structure such as ConcurrentBag, otherwise, some results would be missing because of concurrent write issues.

sawe
  • 1,141
  • 14
  • 24
-3

I believe that you can use IsCompleted like follows:

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