Wait until all or any asynchronous tasks are completed, and the processing scheme for asynchronous tasks to be completed.
This article describes how to wait for all asynchronous tasks to complete, wait for any asynchronous task to complete, and process the asynchronous task to complete.
Wait for the completion of a group of tasks to use the Task. WhenAll method.
Task task1 = Task.Delay(TimeSpan.FromSeconds(1));
Task task2 = Task.Delay(TimeSpan.FromSeconds(2));
Task task3 = Task.Delay(TimeSpan.FromSeconds(3));
await Task.WhenAll(task1, task2, task3);
If all tasks have the same result type and are completed, Task. WhenAll returns an array of the results of each Task.
Task task1 = Task.FromResult(1);
Task task2 = Task.FromResult(2);
Task task3 = Task.FromResult(3);
int[] results = await Task.WhenAll(task1, task2, task3);
foreach(var item in results)
{
Console.WriteLine(item);
}
For example, to provide a url set, you must download the corresponding content remotely based on the url set and write a method.
static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
var httpClient = new HttpClient();
// Define the usage of each ulr
var downloads = urls.Select(url => httpClient.GetStringAsync(url));
// Download start
Task<string>[] downloadTasks = downloads.ToArray();
// Asynchronous waiting
string[] hmtls = await Task.WhenAll(downloadTasks);
return string.Concat(htmls);
}
What if an exception occurs while waiting for all tasks to be completed?
If you want to capture exceptions while waiting, place the WhenAll method in the try statement block. If you want to capture exceptions after all tasks are completed, the Task Type returned by the WhenAll method should be placed in the try statement block.
First, simulate two asynchronous exceptions.
static async Task ThrowNotImplementedExceptionAsync()
{
throw new NotImplementedException();
}
static async Task ThrowInvalidOperationExceptionAsync()
{
throw new InvalidOperationException();
}
First, let's look at the exception handling when the result is returned.
stati async Task ObserveOneExceptionAsync()
{
var task1 = ThrowNotImplementedExceptionAsync();
var task2 = ThrwoInvalidOperationExceptionAsync();
try
{
await Task.WhenAll(task1, ask2);
}
cach(Exception ex)
{
}
}
Let's take a look at the exception handling after all the results come out.
static async Task ObserveAllExceptionAsync()
{
var task1 = ThrowNotImplementedExceptionAsync();
var task2 = ThrwoInvalidOperationExceptionAsync();
Task allTasks = Task.WhenAll(task1, task2);
try
{
await allTasks;
}
catch(Eexception ex)
{
}
}
Wait for the completion of any task to use the WhenAny method.
For example, two tasks are available, and two URLs are used to obtain asynchronous remote content.
private static async Task<int> DownloadAsync(string url1, url2)
{
var httpClient = new HttpClient();
Task<byte[]> download1 = httpClient.GetByteArrayAsync(url1);
Task<byte[]> download2 = httpClient.GetByteArrayAsync(url2);
// Wait for any task to complete
Task<byte[]> completedTask = await Task.WhenAny(download1, download2);
byte[] data = await completedTask;
return data.Length;
}
What should I do when the task is completed?
There are two ways of thinking: one is to generate results according to the order we arranged, and the other is to naturally output results according to the sequence of results produced by the task itself.
First, use an Asynchronous Method.
static async Task<int> DelayAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
Write another method to manually deploy the task sequence.
static async Task ProcessTasksAsync()
{
// Create a task queue
Task<int> task1 = DelayAsync(2);
Task<int> task2 = DelayAsync(3);
Task<int> task3 = DelayAsync(1);
// Manually arrange the task sequence
var tasks = new[]{task1, task2, task3};
// Traverse the task list in order and output results one by one
foreach(var task in tasks)
{
var result = await task;
Console.Write(result);
}
}
The output result is 231, Which is output according to the sequence of tasks manually arranged.
What if we want to output 123? That is, the results will naturally occur according to different tasks.
The idea is to process the output result asynchronously.
You can write an Asynchronous Method for each task.
static async Task AwaitAndProessAync(Task<int> task)
{
var result = await task;
Console.Write(result);
}
The method for modifying ProcessTasksAsync is as follows:
static async Task ProcessTasksAsync()
{
// Create a task queue
Task<int> task1 = DelayAsync(2);
Task<int> task2 = DelayAsync(3);
Task<int> task3 = DelayAsync(1);
// Manually arrange the task sequence
var tasks = new[]{task1, task2, task3};
var processingTasks = (from t in tasks
select AwaitAndProessAync(t)).ToArray();
await Task.WhenAll(processingTasks);
}
You can also modify the ProcessTasksAsync method.
static async Task ProcessTasksAsync()
{
// Create a task queue
Task<int> task1 = DelayAsync(2);
Task<int> task2 = DelayAsync(3);
Task<int> task3 = DelayAsync(1);
// Manually arrange the task sequence
var tasks = new[]{task1, task2, task3};
var processingTasks = tasks.Select( async t => {
var result = await t;
Console.Write(result);
}).ToArray();
await Task.WhenAll(processingTasks);
}
Reference: C # typical concurrent programming instance