Task.WhenEach in .NET: Process Tasks as They Complete



This content originally appeared on DEV Community and was authored by Morteza Jangjoo

When you work with asynchronous programming in .NET, you often deal with multiple tasks running in parallel. Traditionally, we use:

  • Task.WhenAll – waits for all tasks to finish.
  • Task.WhenAny – continues as soon as one task finishes.

But what if you want to process each task as it completes, without waiting for the slowest one?
Enter Task.WhenEach (introduced in .NET 6+).

Why Task.WhenEach?

Imagine calling several APIs with different response times. Using Task.WhenAll, you must wait for the slowest API before processing results.

Task.WhenEach allows you to:

  • Process results immediately as each task finishes.
  • Improve responsiveness in partial-result scenarios.
  • Reduce latency in real-time or streaming-like applications.

Examples

Using Task.WhenAll

var tasks = new[]
{
    Task.Delay(3000).ContinueWith(_ => "Task 1"),
    Task.Delay(1000).ContinueWith(_ => "Task 2"),
    Task.Delay(2000).ContinueWith(_ => "Task 3")
};

var results = await Task.WhenAll(tasks);
foreach (var result in results)
{
    Console.WriteLine($"Processed: {result}");
}

Output order:

Processed: Task 1
Processed: Task 2
Processed: Task 3

Even though Task 2 finished first, results are processed after all tasks complete.

Using Task.WhenEach

await foreach (var task in Task.WhenEach(tasks))
{
    Console.WriteLine($"Processed: {await task}");
}

Output order:

Processed: Task 2
Processed: Task 3
Processed: Task 1

Now, each result is processed as soon as its task finishes, giving you faster responsiveness.

Real-World Use Cases

  1. API Aggregation – Fetch multiple external APIs simultaneously.
  2. File Processing – Handle large files one by one.
  3. Web Crawling – Return partial results to users progressively.
  4. Streaming Scenarios – Act on data incrementally instead of waiting for all of it.

When to Use Which

  • Task.WhenAll – when all results are needed before proceeding.
  • Task.WhenAny – when you only care about the first completed task.
  • Task.WhenEach – when you want to process tasks progressively.

Conclusion

Task.WhenEach is a game-changer for asynchronous programming in .NET.
It helps write more responsive applications and handle tasks efficiently without waiting for the slowest operation.

If you haven’t tried it yet, start replacing some WhenAll scenarios with WhenEach and see the difference.

💡 Tip: Combine Task.WhenEach with async streams (await foreach) to build responsive APIs or real-time dashboards.

I’m Morteza Jangjoo and “Explaining things I wish someone had explained to me”


This content originally appeared on DEV Community and was authored by Morteza Jangjoo