-1

I need to run concurrently 3 or more tasks using a Task.WhenAll, once Task.WhenAll is done executing all tasks I want to capture the result of all tasks.

How to get the result of those tasks that were executed using Task.WhenAll?

Should I use .Result or await? And why?

Would .Result be blocking?

This is the code example:

var task1 = Task1();
var task2 = Task2();
var task3 = Task3();

await Task.WhenAll(task1, task2, task3);

// 1st approach:
var result1 = task1.Result;
var result2 = task2.Result;
var result3 = task3.Result;

// 2nd approach:
var result1 = await task1;
var result2 = await task2;
var result3 = await task3;
ncve
  • 85
  • 9
  • ... or 2nd approach without `Task.WhenAll` ... – Selvin Dec 04 '19 at 15:52
  • IMHO the second approche its 1 LOC less then the first – Isparia Dec 04 '19 at 15:52
  • 1
    How do you define "best"? – Gabriel Luci Dec 04 '19 at 15:55
  • `.Result` is blocking unless the Task is already resolved by that point. Everything else is just a matter of what the business logic needs. Either tasks can run concurrently or they need to be run sequentially. Pick the option that works for what's needed. – JBC Dec 04 '19 at 15:56
  • @Selvin but that way we won't benefit from executing the tasks concurrently – ncve Dec 04 '19 at 15:57
  • task != concurrency ... on the other hand - Task.Run is using "new thread"(in fact some thread pool) and it will executed without await concurrently anyway – Selvin Dec 04 '19 at 15:57
  • @GabrielLuci performance wise and also which one is the best practice – ncve Dec 04 '19 at 15:58
  • @JBC I'm using Task.WhenAll to run the tasks concurrently and I'm wondering which one of these approaches is the best, I mean, performance wise. Is there a change that the Task.WhenAll hasn't finished yet when we get to the 1st `.Result`? – ncve Dec 04 '19 at 16:02
  • Possible duplicate: [Await on a completed task same as task.Result?](https://stackoverflow.com/questions/24623120/await-on-a-completed-task-same-as-task-result) – Theodor Zoulias Dec 04 '19 at 16:11
  • @Selvin I updated the question – ncve Dec 04 '19 at 16:28

1 Answers1

2

Assuming you want to get all three jobs done and none of them depend on the other, then use Task.WhenAll() and/or await each separately after you start them. You don't necessarily need to use both.

var task1 = Task1();
var task2 = Task2();
var task3 = Task3();

Asynchronous methods always start running synchronously. So when you call Task1(), it will run until the first await that acts on an incomplete Task. That will be when it starts waiting for whatever I/O request you're making. At that point, Task1() returns an incomplete Task, and execution proceeds to the next line: running Task2(), etc.

That makes the best use of resources since you use the time that you're waiting for a response in Task1() to start the next request in Task2(), etc.

If you use await Task.WhenAll, the current thread is freed to do other work. The three tasks may very well resume on the current thread once they're done waiting (depending on a few things), one after the other, in whatever order their respective requests had finished. Once they're all done, execution will proceed to the next line after await Task.WhenAll.

This:

var result1 = await task1;
var result2 = await task2;
var result3 = await task3;

is very similar as doing Task.WhenAll() (since you already started the tasks earlier). But here you are capturing the results returned from each. If you need to use the results, then you should use this.

If you use Task.WhenAll() before await task1 then you will be waiting for all three to complete before you start using the result from task1. If you can use the result from task1 before the other tasks complete, then there is no need to use Task.WhenAll().

This:

var result1 = task1.Result;
var result2 = task2.Result;
var result3 = task3.Result;

will block the current thread until task1 is completed. That may very well deadlock if the task needs to resume in the current context. See here for an explanation why: Don't Block on Async Code

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84