Task.WhenAll and Task.WhenAny
Awaiting several operations one after another wastes the whole point of async, if they don't depend on each other, start them all at once.
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
Task<string> t1 = DownloadAsync("https://example.com/a");
Task<string> t2 = DownloadAsync("https://example.com/b");
Task<string> t3 = DownloadAsync("https://example.com/c");
string[] results = await Task.WhenAll(t1, t2, t3);
Console.WriteLine($"Got {results.Length} pages");
}
static async Task<string> DownloadAsync(string url)
{
using var client = new System.Net.Http.HttpClient();
return await client.GetStringAsync(url);
}
}
The pieces
- Calling
DownloadAsync(...)withoutawaitstarts the task immediately and returns aTask<string>you can hold onto, the download runs in the background right away. await Task.WhenAll(t1, t2, t3)waits for all three to finish, and (forTask<T>) returns an array of their results in the same order they were passed in, even if they finish in a different order.- Awaiting each one individually,
await t1; await t2; await t3;, would run them one after another instead of concurrently, three times slower for three independent, equally-long downloads. Task.WhenAny(...)instead resolves as soon as the first task finishes, useful for a timeout pattern: race the real operation againstTask.Delay(timeout)and see which finishes first.
When not to do this
If one operation depends on another's result, keep them sequential with separate awaits, Task.WhenAll is for genuinely independent work, forcing dependent operations to run "concurrently" just creates bugs.