• 异步编程时如何同步等待多个异步 task 的返回结果 ?
  • 发布于 2个月前
  • 344 热度
    0 评论
  • 奥特蛋
  • 1 粉丝 42 篇博客
  •   
问题:
我需要在 Console 程序中运行多个异步Task,在进一步处理之前我需要等待它们全部完成,我看了很多相关文章,但越来越糊涂,我知道可以将 task 链起来从而实现一个task的异步串行,但我希望多个task一起运行并在后续的某个点上一次获取所有的结果。

请问是否有最简单的实现方式。


解决方案:

方案一.

你可以使用 WhenAll,它返回的是一个可等待的 Task 类,你也可以使用 WaitAll,它没有返回值,但可以实现类似 Thread.Sleep 式的阻塞,直到所有的 tasks 完成,取消或者失败。
下面是一些详细的区别。
发生异常时
1,WhenALL
它会返回一个带失败状态的task,异常信息会包含在这个失败task的 AggregateException 中。
2.WaitAll

会直接抛出 AggregateException 异常。


任务被取消时
1.WhenALL
返回Task的任务状态是 TaskStatus.Canceled。
2.WaitAll

会抛出 AggregateException 异常,内部的异常类型是 OperationCanceledException。


线程阻塞
WhenALL
不会阻塞当前线程。
WaitAll
会阻塞当前线程。
参考如下代码:
var tasks = new Task[] {
    TaskOperationOne(),
    TaskOperationTwo()
};

Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);

方案二
完全可以使用阻塞版本的 Task.WaitAll 来实现。
List<Task> TaskList = new List<Task>();
foreach(...)
{
   var LastTask = new Task(SomeFunction);
   LastTask.Start();
   TaskList.Add(LastTask);
}

Task.WaitAll(TaskList.ToArray());
当然你也可以用  async + await 再配 WhenAll 来实现完全异步,参考如下代码:
var cats = new List<Cat>();
var dog = new Dog();

var loadDataTasks = new Task[]
{
    Task.Run(async () => cats = await LoadCatsAsync()),
    Task.Run(async () => dog = await LoadDogAsync())
};

try
{
    await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
    // handle exception
}
总结:
这种等待多个 Task 的完成状态,一般都是用 WaitAll 和 WhenAll 两种方式实现,当然在 .NET6 中新增了 Parallel.ForEachAsync 方法来是实现异步并发,有兴趣的朋友可以了解下。
用户评论