1

I've already search and read about, I just want to make sure if I am right. I have three methods that I want to run in parallel, and I want to make sure that all of them are done before continue. They are all async, and this code are inside an async method. I've done this:

public async ProcessBegin() {
   //... some code

   await SomeProcess();
   await AnotherMethod().
}

public async SomeProcess() {
   //.. some code    

   var tasks = new Task[3];
   tasks[0] = method1();
   tasks[1] = method2();
   tasks[2] = method3();

   Task.WaitAll(tasks);
}

public async Method1(){...}
public async Method2(){...}
public async Method3(){...}

Is this right?

Leandro Souza
  • 69
  • 1
  • 11
  • This could potentially cause a deadlock; can you provide some more context? Is this method synchronous? – Johnathan Barclay Feb 18 '20 at 11:52
  • 1
    Have a look at `await Task.WhenAll(tasks);` possibility – Dmitry Bychenko Feb 18 '20 at 11:53
  • 1
    Usually, it's "async all the way" meaning that the code you have shown itself is a method that returns a Task and instead of `Task.WaitAll(tasks);` it should be `await Task.WhenAll(tasks);`. You don't need to construct the Task array either as `Task.WaitAll`/ `WhenAll` have the signature `params Task[] tasks` - so `await Task.WhenAll(method1(), method2(), method3());`. – ckuri Feb 18 '20 at 11:54
  • Put few breakpoints, press F5 and you will see if you are doing it right :D – Veljko89 Feb 18 '20 at 11:55
  • You forgot to start tasks using the [Start](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.start?view=netframework-4.8) method. But it's better to use [Task.Run](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run?view=netframework-4.8). It's even better to use Parallel.Invoke. – Alexander Petrov Feb 18 '20 at 11:58
  • 1
    According to the [guidelines](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap#naming-parameters-and-return-types) the methods `Method1`, `Method2` and `Method3` should be named `Method1Async`, `Method2Async` and `Method3Async`. – Theodor Zoulias Feb 18 '20 at 12:03

2 Answers2

4

Task.WaitAll blocks synchronously so you might use Parallel.Invoke if this is intended:

Parallel.Invoke(() => method1(), () => method2(), () => method3());

This works as long as the methodX methods themselves are not asynchronous. Parallel.ForEach doesn't work with async actions.

If you want to wait for the tasks to complete asynchronously, you should use Task.WhenAll:

var tasks = new Task[3];
tasks[0] = method1();
tasks[1] = method2();
tasks[2] = method3();

await Task.WhenAll(tasks);
mm8
  • 163,881
  • 10
  • 57
  • 88
  • 4
    An important point here is the signature of method1/2/3. If they are non-async, `Parallel.Invoke` is preferable. If they are async in nature, you can't use `Parallel.Invoke` and should use `Task.WhenAll`. – ckuri Feb 18 '20 at 11:59
  • It is valid to say that when you use WhenAll() it will wait for all tasks to be completed, even if it has an failure in one of them – Heitor Ribeiro Feb 18 '20 at 12:00
  • @ckuri: That's a great point. I edited my answer to clarify this. – mm8 Feb 18 '20 at 12:03
  • @mm8 Using that way will run these methods in parallel? – Leandro Souza Feb 18 '20 at 13:26
  • 1
    @LeandroSouza: `Task.WhenAll`? Yes, provided that `methodX` starts and returns an incomplete task. – mm8 Feb 18 '20 at 13:28
3
public async Task SomeProcess()
{
    //.. some code    

    await Task.WhenAll(method1(), method2(), method3());
}

Use Task.WhenAll which returns a new Task that completes once all the provided tasks have also completed.

You don't need to create the array manually because Task.WhenAll accepts params Task[].

Using Task.WaitAll, as you have tried, will block the current thread until the tasks complete, hence rendering the method synchronous.

Furthermore, it could cause deadlocks depending on the synchronisation context of your app, as method1 / method2 / method3 may attempt to resume on the thread blocked by WaitAll.

Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35