Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Awaiting multiple Tasks with different results

I have 3 tasks:

private async Task<Cat> FeedCat() {}
private async Task<House> SellHouse() {}
private async Task<Tesla> BuyCar() {}

They all need to run before my code can continue and I need the results from each as well. None of the results have anything in common with each other

How do I call and await for the 3 tasks to complete and then get the results?

like image 753
Ian Vink Avatar asked Jun 19 '13 17:06

Ian Vink


People also ask

How do you wait for multiple tasks?

The correct way to await multiple tasks is the Task. WhenAll method: await Task. WhenAll(first, second); . Then you can await them individually to get their results, because you know that all have completed successfully.

Is Task result the same as await?

await asynchronously unwraps the result of your task, whereas just using Result would block until the task had completed.

What does awaiting a task do?

The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, the await operator returns the result of the operation, if any.

What happens if you don't await a task?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.


3 Answers

After you use WhenAll, you can pull the results out individually with await:

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

await Task.WhenAll(catTask, houseTask, carTask);

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

You can also use Task.Result (since you know by this point they have all completed successfully). However, I recommend using await because it's clearly correct, while Result can cause problems in other scenarios.

like image 179
Stephen Cleary Avatar answered Oct 16 '22 19:10

Stephen Cleary


Just await the three tasks separately, after starting them all.

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

var cat = await catTask;
var house = await houseTask;
var car = await carTask;
like image 30
Servy Avatar answered Oct 16 '22 18:10

Servy


If you're using C# 7, you can use a handy wrapper method like this...

public static class TaskEx
{
    public static async Task<(T1, T2)> WhenAll<T1, T2>(Task<T1> task1, Task<T2> task2)
    {
        return (await task1, await task2);
    }
}

...to enable convenient syntax like this when you want to wait on multiple tasks with different return types. You'd have to make multiple overloads for different numbers of tasks to await, of course.

var (someInt, someString) = await TaskEx.WhenAll(GetIntAsync(), GetStringAsync());

However, see Marc Gravell's answer for some optimizations around ValueTask and already-completed tasks if you intend to turn this example into something real.

like image 52
Joel Mueller Avatar answered Oct 16 '22 19:10

Joel Mueller