C#AsyncIntermediate

Task.WhenAll()

Creates a task that will complete when all of the provided tasks have completed, whether successfully, by faulting, or by being canceled.

Review the syntaxStudy the examplesOpen the coding app
Task Task.WhenAll(params Task[] tasks)

This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.

What it does

Overview

Creates a task that will complete when all of the provided tasks have completed, whether successfully, by faulting, or by being canceled.

`Task.WhenAll()` is a powerful method in C# for orchestrating multiple asynchronous operations concurrently. It takes an array or `IEnumerable` of `Task` or `Task<TResult>` objects and returns a single `Task`. This returned task completes only when *all* the input tasks have finished their execution. If all input tasks complete successfully, the `WhenAll` task also completes successfully. If any of the input tasks fault, the `WhenAll` task will also fault, and its `Exception` property will contain an `AggregateException` that wraps all the exceptions from the faulted tasks. If any task is canceled, the `WhenAll` task will also be canceled. This method is crucial for scenarios where you need to perform several independent asynchronous operations in parallel and then wait for all of them to finish before proceeding. For example, fetching data from multiple APIs simultaneously. Time complexity is not directly applicable to `WhenAll` itself, but the overall execution time will be dominated by the longest-running task among the collection. Edge cases include passing an empty collection (returns an already completed task), or a collection containing `null` tasks (throws `ArgumentNullException`). Best practices involve using `WhenAll` to maximize concurrency for independent operations, and always `await`ing the result to properly observe any potential exceptions from the constituent tasks.

Quick reference

Syntax

Task Task.WhenAll(params Task[] tasks)

Inputs

Parameters

tasksIEnumerable<Task> or IEnumerable<Task<TResult>> · The tasks to wait for.

See it in practice

Examples

1

Waiting for multiple void tasks to complete

using System.Threading.Tasks;
using System;

public class WhenAllVoidExample
{
    public static async Task DoWork(string name, int delay)
    {
        Console.WriteLine($"{name} starting...");
        await Task.Delay(delay);
        Console.WriteLine($"{name} finished.");
    }

    public static async Task Main()
    {
        Task task1 = DoWork("Task A", 2000);
        Task task2 = DoWork("Task B", 1000);
        Task task3 = DoWork("Task C", 1500);

        Console.WriteLine("Waiting for all tasks...");
        await Task.WhenAll(task1, task2, task3);
        Console.WriteLine("All tasks completed.");
    }
}
Output:
Waiting for all tasks... Task A starting... Task B starting... Task C starting... Task B finished. Task C finished. Task A finished. All tasks completed.

Launches three independent tasks and waits for all of them to finish before proceeding.

2

Waiting for multiple tasks with results

using System.Threading.Tasks;
using System;
using System.Linq;

public class WhenAllResultExample
{
    public static async Task<int> GetNumberAsync(int id, int delay)
    {
        await Task.Delay(delay);
        return id * 10;
    }

    public static async Task Main()
    {
        Task<int> num1 = GetNumberAsync(1, 1000);
        Task<int> num2 = GetNumberAsync(2, 500);
        Task<int> num3 = GetNumberAsync(3, 1200);

        int[] results = await Task.WhenAll(num1, num2, num3);
        Console.WriteLine($"Results: {string.Join(", ", results)}");
        Console.WriteLine($"Sum: {results.Sum()}");
    }
}
Output:
Results: 10, 20, 30 Sum: 60

Collects results from multiple `Task<T>` objects after all have completed, returning an array of `T`.

3

Handling exceptions from WhenAll

using System.Threading.Tasks;
using System;

public class WhenAllErrorExample
{
    public static async Task FailTask(string name, int delay, bool shouldFail)
    {
        await Task.Delay(delay);
        if (shouldFail) throw new Exception($"{name} failed!");
        Console.WriteLine($"{name} succeeded.");
    }

    public static async Task Main()
    {
        Task t1 = FailTask("Task X", 500, false);
        Task t2 = FailTask("Task Y", 1000, true);
        Task t3 = FailTask("Task Z", 700, false);

        try
        {
            await Task.WhenAll(t1, t2, t3);
        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
            {
                Console.WriteLine($"Caught exception: {ex.Message}");
            }
        }
    }
}
Output:
Task X succeeded. Task Z succeeded. Caught exception: Task Y failed!

`WhenAll` wraps exceptions from multiple faulted tasks into an `AggregateException`.

Debug faster

Common Errors

1

Logical Error

Cause: Not `await`ing the `Task.WhenAll` result, which can lead to unobserved exceptions if any of the constituent tasks fail.

Fix: Always `await` the `Task.WhenAll` call within a `try-catch` block to properly handle any `AggregateException` that might occur.

Task t1 = Task.Run(() => { throw new Exception("Error!"); });
Task.WhenAll(t1); // Exception might go unobserved if not awaited

Runtime support

Compatibility

.NETN/A.NET Framework 4.0+, .NET Core 1.0+

Source: Microsoft Learn

Common questions

Frequently Asked Questions

Creates a task that will complete when all of the provided tasks have completed, whether successfully, by faulting, or by being canceled.

tasks: The tasks to wait for.

Logical Error: Always `await` the `Task.WhenAll` call within a `try-catch` block to properly handle any `AggregateException` that might occur.