等待所有或任意异步任务完成,以及异步任务完成时的处理方案

 

本篇体验如何等待所有异步任务完成、等待任意一个异步任务完成,以及异步任务完成时的处理。

 

等待一组任务的完成使用Task.WhenAll方法。

 

 
 
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);
 
 

 

如果所有任务的结果类型相同且全部完成,Task.WhenAll返回每个任务执行结果的数组。

 

 
 
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);
}

 

举个例子,提供一个url的集合,要求根据这个url集合去远程下载对应的内容,写一个方法。

 

 
 
static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
    var httpClient = new HttpClient();
 
 
    //定义每一个ulr的使用方法
    var downloads = urls.Select(url => httpClient.GetStringAsync(url));
 
 
    //下载真正开始
    Task<string>[] downloadTasks = downloads.ToArray();
 
 
    //异步等待
    string[] hmtls = await Task.WhenAll(downloadTasks);
 
 
    return string.Concat(htmls);
}
 
 

 

如果在等待所有任务完成的过程中有异常发生怎么办呢?

 

如果想在等待过程中捕获异常,那么应该把WhenAll方法放在try语句块中;如果想在所有任务完成后捕获异常,那就应该把WhenAll方法返回的Task类型放在try语句块中。

 

先模拟两个异步异常。

 

 
 
static async Task ThrowNotImplementedExceptionAsync()
{
    throw new NotImplementedException();
}
 
 
static async Task ThrowInvalidOperationExceptionAsync()
{
    throw new InvalidOperationException();
}
 
 

 

首先来看等待结果出来时的异常处理。

 

 
 
stati async Task ObserveOneExceptionAsync()
{
    var task1 = ThrowNotImplementedExceptionAsync();
    var task2 = ThrwoInvalidOperationExceptionAsync();
 
 
    try
    {
        await Task.WhenAll(task1, ask2);
    }
    cach(Exception ex)
    {
 
 
    }
}
 
 

 

再来看等所有结果出来后的异常处理。

 

 
 
static async Task ObserveAllExceptionAsync()
{
    var task1 = ThrowNotImplementedExceptionAsync();
    var task2 = ThrwoInvalidOperationExceptionAsync();
 
 
    Task allTasks = Task.WhenAll(task1, task2);
 
 
    try
    {
        await allTasks;
    }
    catch(Eexception ex)
    {
 
 
    }
}
 
 

 

等待任意一个任务的完成使用WhenAny方法。

 

比如有2个任务,通过2个url获取异步远程内容。

 

 
 
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);
 
 
    //等待任意一个任务完成
    Task<byte[]> completedTask = await Task.WhenAny(download1, download2);
 
 
    byte[] data = await completedTask;
    return data.Length;
}
 
 

 

任务完成时如何处理呢?

 

思路有2个,一个是根据我们安排的顺序出结果,还有一个是根据任务本身出结果的先后顺序自然输出结果。

 

首先来一个异步方法。

 

 
 
static async Task<int> DelayAsync(int val)
{
    await Task.Delay(TimeSpan.FromSeconds(val));
    return val;
}

 

再写一个手动部署任务顺序的方法。

 

 
 
static async Task ProcessTasksAsync()
{
    //创建任务队列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
 
 
    //手动安排任务的顺序
    var tasks = new[]{task1, task2, task3};
 
 
    //按顺序遍历任务列表,逐一输出结果
    foreach(var task in tasks)
    {
        var result = await task;
        Console.Write(result);
    }
}
 
 

 

输出结果为231,是根据我们手动安排任务的顺序输出结果的。

 

如果我们想输出123呢?即按照任务的不同让结果自然发生。

 

思路是:以异步的方式处理输出结果。

 

可以写一个针对每个任务的异步方法。

 

 
 
static async Task AwaitAndProessAync(Task<int> task)
{
    var result = await task;
    Console.Write(result);
}

 

现在修改ProcessTasksAsync方法如下:

 

 
 
static async Task ProcessTasksAsync()
{
    //创建任务队列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
 
 
    //手动安排任务的顺序
    var tasks = new[]{task1, task2, task3};
 
 
    var processingTasks = (from t in tasks
                        select AwaitAndProessAync(t)).ToArray();
 
 
     await Task.WhenAll(processingTasks);                    
}
 
 

 

当然,也可以这样修改ProcessTasksAsync方法。


 
 
static async Task ProcessTasksAsync()
{
    //创建任务队列
    Task<int> task1 = DelayAsync(2);
    Task<int> task2 = DelayAsync(3);
    Task<int> task3 = DelayAsync(1);
 
 
    //手动安排任务的顺序
    var tasks = new[]{task1, task2, task3};
 
 
    var processingTasks = tasks.Select( async t => {
        var result = await t;
        Console.Write(result);
    }).ToArray();
                        
 
 
     await Task.WhenAll(processingTasks);                    
}
 
 
 
 

 

参考资料:C#并发编程经典实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值