【问题标题】:C# How to capture the tasks result in a Task.WhenAll? ".Result" or "await" [closed]C#如何在Task.WhenAll中捕获任务结果? “.Result”或“await”[关闭]
【发布时间】:2019-12-04 15:48:40
【问题描述】:

我需要使用 Task.WhenAll 同时运行 3 个或更多任务,一旦 Task.WhenAll 完成执行所有任务,我想捕获所有任务的结果。

如何获取那些使用 Task.WhenAll 执行的任务的结果?

我应该使用.Result 还是await?为什么?

.Result 会被屏蔽吗?

这是代码示例:

var task1 = Task1();
var task2 = Task2();
var task3 = Task3();

await Task.WhenAll(task1, task2, task3);

// 1st approach:
var result1 = task1.Result;
var result2 = task2.Result;
var result3 = task3.Result;

// 2nd approach:
var result1 = await task1;
var result2 = await task2;
var result3 = await task3;

【问题讨论】:

  • ...或没有Task.WhenAll的第二种方法...
  • 恕我直言,第二个比第一个少 1 个 LOC
  • 你如何定义“最佳”?
  • .Result 是阻塞的,除非此时任务已经解决。其他一切都只是业务逻辑需要的问题。任务可以同时运行,也可以按顺序运行。选择适合所需的选项。
  • @Selvin 但这样我们不会从并发执行任务中受益

标签: c# .net asynchronous async-await task


【解决方案1】:

假设您想完成所有三个工作并且它们都不依赖于另一个,那么在您启动它们之后分别使用Task.WhenAll() 和/或await。您不一定需要同时使用两者。

var task1 = Task1();
var task2 = Task2();
var task3 = Task3();

异步方法总是同步开始运行。因此,当您调用Task1() 时,它将一直运行到第一个作用于不完整Taskawait。那将是它开始等待您提出的任何 I/O 请求的时候。此时,Task1() 返回一个不完整的Task,并继续执行下一行:运行Task2(),等等。

这样可以充分利用资源,因为您使用等待Task1() 响应的时间来启动Task2() 中的下一个请求等。

如果你使用await Task.WhenAll,当前线程被释放来做其他工作。一旦完成等待(取决于一些事情),这三个任务很可能会在当前线程上恢复,一个接一个,无论它们各自的请求完成的顺序如何。全部完成后,将继续执行await Task.WhenAll 之后的下一行。

这个:

var result1 = await task1;
var result2 = await task2;
var result3 = await task3;

Task.WhenAll() 非常相似(因为您之前已经开始了这些任务)。但是在这里,您正在捕获每个返回的结果。如果你需要使用结果,那么你应该使用这个。

如果您使用Task.WhenAll() 之前 await task1,那么在开始使用task1 的结果之前,您将等待所有三个完成。如果您可以在其他任务完成之前使用来自task1 的结果,则无需使用Task.WhenAll()

这个:

var result1 = task1.Result;
var result2 = task2.Result;
var result3 = task3.Result;

将阻塞当前线程直到task1 完成。如果任务需要在当前上下文中恢复,那很可能会出现死锁。请参阅此处了解原因:Don't Block on Async Code

【讨论】:

    猜你喜欢
    • 2012-11-06
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多