Explain the difference between `Task.WhenAll()` and `Task.WhenAny()`

4 minintermediate.NETasync-awaitTaskconcurrency

Quick Answer

`Task.WhenAll()` returns a task that completes when *all* supplied tasks finish (aggregating results and exceptions), so it's used to run independent operations concurrently and wait for every one. `Task.WhenAny()` completes as soon as *any* one task finishes, returning that task — useful for timeouts, first-response-wins, or redundancy. Both are non-blocking and awaitable.

Detailed Answer

Task.WhenAll() waits for all tasks in a collection to complete before continuing. It returns a task that completes when all input tasks have completed.

Key characteristics of Task.WhenAll():

  • Waits for ALL tasks to finish
  • Returns an array of results (if tasks return values)
  • If any task throws an exception, the returned task will be faulted
  • All exceptions are aggregated in an AggregateException
  • Useful for parallel execution where you need all results
// Example: Download multiple files concurrently
var task1 = DownloadFileAsync("file1.txt");
var task2 = DownloadFileAsync("file2.txt");
var task3 = DownloadFileAsync("file3.txt");

// Wait for all downloads to complete
await Task.WhenAll(task1, task2, task3);
Console.WriteLine("All files downloaded");

Task.WhenAny() returns as soon as ANY one of the tasks completes. It returns a task that represents the first completed task.

Key characteristics of Task.WhenAny():

  • Returns when the FIRST task completes
  • Returns the completed task itself (not the result)
  • Useful for timeout scenarios or racing multiple operations
  • Other tasks continue running in the background
// Example: Implement timeout pattern
var dataTask = FetchDataAsync();
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));

var completedTask = await Task.WhenAny(dataTask, timeoutTask);

if (completedTask == timeoutTask)
{
    throw new TimeoutException("Operation timed out");
}

var result = await dataTask;

Related Resources