Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to run multiple async tasks and waiting for them all to complete in C#?
In C#, there are several ways to run multiple asynchronous tasks and wait for them all to complete. The two main approaches are Task.WaitAll (synchronous blocking) and Task.WhenAll (asynchronous non-blocking).
Task.WaitAll blocks the current thread until all tasks have completed execution, while Task.WhenAll returns a task that completes when all provided tasks have finished, without blocking the calling thread.
Syntax
Following is the syntax for using Task.WaitAll −
Task.WaitAll(task1, task2, task3);
Following is the syntax for using Task.WhenAll −
await Task.WhenAll(task1, task2, task3);
Using Task.WhenAll (Non-blocking)
The Task.WhenAll method creates a task that will complete when all the provided tasks have completed. It does not block the current thread −
using System;
using System.Threading.Tasks;
class Program {
static async Task Main(string[] args) {
Task task1 = Task.Run(async () => {
for (var i = 0; i < 3; i++) {
Console.WriteLine("Task 1 - iteration {0}", i);
await Task.Delay(1000);
}
Console.WriteLine("Task 1 complete");
});
Task task2 = Task.Run(async () => {
for (var i = 0; i < 3; i++) {
Console.WriteLine("Task 2 - iteration {0}", i);
await Task.Delay(1500);
}
Console.WriteLine("Task 2 complete");
});
Console.WriteLine("Starting tasks...");
await Task.WhenAll(task1, task2);
Console.WriteLine("Both Tasks Completed.");
}
}
The output of the above code is −
Starting tasks... Task 1 - iteration 0 Task 2 - iteration 0 Task 1 - iteration 1 Task 1 - iteration 2 Task 1 complete Task 2 - iteration 1 Task 2 - iteration 2 Task 2 complete Both Tasks Completed.
Using Task.WaitAll (Blocking)
The Task.WaitAll method blocks the current thread until all tasks have completed execution −
using System;
using System.Threading.Tasks;
class Program {
static void Main(string[] args) {
Task task1 = Task.Run(async () => {
for (var i = 0; i < 3; i++) {
Console.WriteLine("Task 1 - iteration {0}", i);
await Task.Delay(1000);
}
Console.WriteLine("Task 1 complete");
});
Task task2 = Task.Run(async () => {
for (var i = 0; i < 3; i++) {
Console.WriteLine("Task 2 - iteration {0}", i);
await Task.Delay(1500);
}
Console.WriteLine("Task 2 complete");
});
Console.WriteLine("Waiting for tasks to complete...");
Task.WaitAll(task1, task2);
Console.WriteLine("Both Tasks Completed.");
}
}
The output of the above code is −
Waiting for tasks to complete... Task 1 - iteration 0 Task 2 - iteration 0 Task 1 - iteration 1 Task 1 - iteration 2 Task 1 complete Task 2 - iteration 1 Task 2 - iteration 2 Task 2 complete Both Tasks Completed.
Handling Task Results with Task.WhenAll
When working with tasks that return values, Task.WhenAll can collect all results −
using System;
using System.Threading.Tasks;
class Program {
static async Task Main(string[] args) {
Task<int> task1 = Task.Run(async () => {
await Task.Delay(1000);
Console.WriteLine("Task 1 completed");
return 10;
});
Task<int> task2 = Task.Run(async () => {
await Task.Delay(1500);
Console.WriteLine("Task 2 completed");
return 20;
});
Task<int> task3 = Task.Run(async () => {
await Task.Delay(500);
Console.WriteLine("Task 3 completed");
return 30;
});
int[] results = await Task.WhenAll(task1, task2, task3);
Console.WriteLine("All tasks completed. Results: [{0}]", string.Join(", ", results));
}
}
The output of the above code is −
Task 3 completed Task 1 completed Task 2 completed All tasks completed. Results: [10, 20, 30]
Comparison
| Task.WaitAll | Task.WhenAll |
|---|---|
| Blocks the calling thread | Does not block the calling thread |
| Synchronous operation | Asynchronous operation |
| Cannot be used with await | Can be used with await |
| No return value | Returns results from all tasks |
Conclusion
Use Task.WhenAll with await for asynchronous programming as it doesn't block the calling thread and allows for better scalability. Use Task.WaitAll only when you need synchronous blocking behavior. Both methods ensure all tasks complete before proceeding.
