Explanation
What just happened
await FetchAsync("a") finished before the next line ran, so FetchAsync("b") started only after a was done. The two calls had nothing to do with each other, yet they ran in sequence: about 200 ms.
Try the what-if switch
- Task.WhenAll: both calls are started before anything is awaited. Each runs until its
await, so both waits overlap, andWhenAllfinishes when the slower one does: about 100 ms. The results come back asa b, in the order given.
Why
An async method starts the moment you call it. await is what makes the caller wait. Start everything first, then await them together.
Watch out
If one task throws, await Task.WhenAll(...) rethrows the first exception, but only after every task has finished.
Common questions
Does await run tasks in parallel?
No. await waits for that task before the next line runs, so two awaits in a row run one after the other.
Does Task.WhenAll start the tasks?
No. Calling an async method already starts it: it runs until its first await. Task.WhenAll only waits for tasks that are already running, and returns their results in the order you passed them.
Is Task.WhenAll parallel or concurrent?
For I/O like network calls, the waits overlap. For CPU work, use Task.Run for each piece so they can run on different threads.
Verified: this timeline matches a real program, checked in CI on .NET 8 and 10. How we verify. Unclear or wrong? Tell us