How to use Task.WhenEach in C#
By FoxLearn 1/5/2025 4:55:50 AM 60
Unlike Task.WaitAny, it iterates through tasks as they complete, making it ideal for scenarios with tasks of varying execution times. While Task.WhenAll and Task.WhenAny handle multiple tasks, Task.WhenEach addresses specific limitations of these methods.
Task.WhenEach returns an IAsyncEnumerable, enabling the use of an await foreach loop to process tasks one at a time as they finish. This simplifies and optimizes code by eliminating the need to wait for all tasks to complete or manually manage task completions.
The Task.WhenEach method is part of the Task class in the System.Threading.Tasks namespace.
namespace System.Threading.Tasks; public class Task { public static IAsyncEnumerable WhenEach(params Task[] tasks); public static IAsyncEnumerable WhenEach(params ReadOnlySpan tasks); public static IAsyncEnumerable WhenEach(IEnumerable tasks); }
Suppose we want to simulate processing a series of files asynchronously, each taking a random amount of time to complete.
First, create an async method that simulates file processing:
async Task<string> ProcessFileAsync(string fileName) { var delay = Random.Shared.Next(500, 5000); // Random delay between 500ms and 5000ms await Task.Delay(delay); return $"Processed {fileName} in {delay}ms"; }
This method simulates a file operation with a random delay and then returns a status message.
Next, create a list of file names and initiate tasks using the ProcessFileAsync method:
var fileNames = new List<string> { "File1.txt", "File2.txt", "File3.txt", "File4.txt", "File5.txt" }; var tasks = fileNames.Select(fileName => ProcessFileAsync(fileName)).ToList();
Now, use the Task.WhenEach method to process and display results as each task completes:
await foreach (var task in Task.WhenEach(tasks)) { Console.WriteLine(await task); // Await the task result and display it }
This efficiently processes and prints the result of each file operation as soon as it completes, without waiting for all tasks to finish.
The Task.WhenAny method can achieve similar results but requires extra code to loop through and manage completed tasks.
while (tasks.Any()) { var completedTask = await Task.WhenAny(tasks); tasks.Remove(completedTask); Console.WriteLine(await completedTask); }
Add cancellation logic to the Task.WhenEach method
To incorporate cancellation, you can use a CancellationTokenSource:
using var tokenSource = new CancellationTokenSource(10000); // 10-second timeout var token = tokenSource.Token; await foreach (var task in Task.WhenEach(tasks).WithCancellation(token)) { if (!tokenSource.TryReset()) token.ThrowIfCancellationRequested(); Console.WriteLine(await task); tokenSource.CancelAfter(10_000); // Reset the timeout for each task }
In this example, we use CancellationTokenSource to create a CancellationToken for task cancellation. The ThrowIfCancellationRequested method triggers an OperationCanceledException if cancellation is requested, while the CancelAfter method schedules cancellation after a specified time delay.
The Task.WhenEach method simplifies handling asynchronous tasks by enabling immediate processing of each task as it completes. It reduces the boilerplate code required with methods like Task.WhenAny and enhances application scalability and performance.
- How to fix 'Failure sending mail' in C#
- How to Parse a Comma-Separated String from App.config in C#
- How to convert a dictionary to a list in C#
- How to retrieve the Executable Path in C#
- How to validate an IP address in C#
- How to retrieve the Downloads Directory Path in C#
- C# Tutorial
- Dictionary with multiple values per key in C#