Summary: in this tutorial, you’ll learn how to use the C# WhenAll()
static method of the Task class to create a task that will be completed when all the input tasks are completed.
Introduction to the C# WhenAll() static method
The
method creates a task that will be completed once all the input tasks are completed. The method returns a Task.WhenAll
()Task
object that represents the completion of all the input tasks. The returned task contains the results of all the input tasks.
In practice, the
is useful for aggregating results from multiple asynchronous operations.Task.WhenAll
()
The following program demonstrates the
method:Task.WhenAll
()
static async Task<int> DoWork(int taskId)
{
Console.WriteLine($"Task {taskId} started...");
await Task.Delay(TimeSpan.FromSeconds(taskId));
Console.WriteLine($"Task {taskId} finished.");
return taskId * taskId;
}
var t1 = Task.Run(() => DoWork(1));
var t2 = Task.Run(() => DoWork(2));
var t3 = Task.Run(() => DoWork(3));
int[] results = await Task.WhenAll(t1, t2, t3);
Console.WriteLine("Results:");
Console.WriteLine(string.Join(", ", results));
Code language: C# (cs)
Output:
Task 3 started...
Task 2 started...
Task 1 started...
Task 1 finished.
Task 2 finished.
Task 3 finished.
Results:
1, 4, 9
Code language: C# (cs)
How it works.
First, define a method called DoWork()
that accepts an integer parameter
. The method displays a message indicating that the task has started, and delays for a specified number of seconds using the taskId
method, and displays another message showing that the task has finished and returns the square of the Task.Delay
()
:taskId
static async Task<int> DoWork(int taskId)
{
Console.WriteLine($"Task {taskId} started...");
await Task.Delay(TimeSpan.FromSeconds(taskId));
Console.WriteLine($"Task {taskId} finished.");
return taskId * taskId;
}
Code language: C# (cs)
Since the method has an asynchronous operation, it is marked as an async
method. Hence, it returns a Task<int>
object rather than an integer.
Second, create three tasks using the
method that executes the Task.Run
()DoWork()
method on background threads:
var t1 = Task.Run(() => DoWork(1));
var t2 = Task.Run(() => DoWork(2));
var t3 = Task.Run(() => DoWork(3));
Code language: C# (cs)
Third, use the
method to wait for three tasks to be completed. The method returns an array of integers stored in the results variable:Task.WhenAll
()
int[] results = await Task.WhenAll(t1, t2, t3);
Code language: C# (cs)
Finally, show the results to the console:
Console.WriteLine("Results:");
Console.WriteLine(string.Join(", ", results));
Code language: C# (cs)
Waiting for multiple HTTP requests to complete using Task.WhenAll() method
The following example shows how to use the
and Task.WhenAll
()HttpClient
to fetch contents asynchronously from multiple URLs
and calculate the total bytes:
static async Task<int> Fetch(string url)
{
Console.WriteLine($"Fetching {url}...");
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Fetched {url} ({content.Length} bytes)");
return content.Length;
}
var t1 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc2616"));
var t2 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc2822"));
var t3 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc1180"));
var results = await Task.WhenAll(new[] { t1, t2, t3 });
Console.WriteLine($"Total {results.Sum()} bytes");
Code language: C# (cs)
Output:
Fetching https://www.rfc-editor.org/rfc/rfc2822...
Fetching https://www.rfc-editor.org/rfc/rfc1180...
Fetching https://www.rfc-editor.org/rfc/rfc2616...
Fetched https://www.rfc-editor.org/rfc/rfc2822 (141338 bytes)
Fetched https://www.rfc-editor.org/rfc/rfc1180 (80606 bytes)
Fetched https://www.rfc-editor.org/rfc/rfc2616 (521792 bytes)
Total 743736 bytes
Code language: C# (cs)
How it works.
First, define the Fetch()
method that takes a string argument url
and returns a Task<int>
object:
static async Task<int> Fetch(string url)
{
Console.WriteLine($"Fetching {url}...");
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Fetched {url} ({content.Length} bytes)");
return content.Length;
}
Code language: C# (cs)
The Fetch()
method uses the HttpClient
object to fetch the contents of the input url
asynchronously. Once it completes downloading the contents of the URL, it gets the size of the contents in bytes. and return it as the integer value wrapped in a Task
object.
Second, create three tasks using the Task.Run
method to execute the Fetch()
method asynchronously:
var t1 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc2616"));
var t2 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc2822"));
var t3 = Task.Run(() => Fetch("https://www.rfc-editor.org/rfc/rfc1180"));
Code language: C# (cs)
Third, wait for all three tasks to be completed using the
method and return an array of their results as Task.WhenAll
()Task<int[]>
object:
var results = await Task.WhenAll(new[] { t1, t2, t3 });
Code language: C# (cs)
Finally, calculate the total size of the fetched contents by adding up the size of the content of each task using the Sum()
extension method and display the result:
Console.WriteLine($"Total {results.Sum()} bytes");
Code language: C# (cs)
Summary
- Use the
method to create a task that will be completed once all the input tasks have finished.Task.WhenAll
()