C# Async Programming: Task, async/await & Cancellation

Lesson 3 of 7

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(...) without await starts the task immediately and returns a Task<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 (for Task<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 against Task.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.

📝 WhenAll & WhenAny Quiz

Passing score: 70%
  1. 1.What does Task.WhenAll(t1, t2, t3) do?

  2. 2.Task.____ resolves as soon as the first of several tasks finishes, useful for timeout patterns.

  3. 3.Calling an async method without awaiting it immediately starts the work in the background.