【问题标题】:Does await Task.WhenAll in C# .NET block?C# .NET 中的 await Task.WhenAll 是否会阻塞?
【发布时间】:2020-07-12 21:57:54
【问题描述】:

当谈到 .NET 中的 async/await 时,我有点困惑......

考虑以下方法:

public async Task DoSomething() {
   IEnumerable<Task> ts = GetSomeTasks(); // Some tasks that would do some random IO stuff, or whatever
   await Task.WhenAll(ts);
   Console.WriteLine("All tasks completed!");
}

Console.WriteLine 的调用是否保证在等待ts 中的任务之后执行?我想我已经看到在访问任务结果之前等待似乎不会像那样“阻塞”的情况。适用什么规则?

【问题讨论】:

  • 您可能已经看到人们无意中创建了Task&lt;Task&gt;s(或Task&lt;Task&lt;T&gt;&gt;s)的一些情况——外部Task 可以轻松完成,但内部任务(实际工作)却不是尚未完成
  • @PavelAnikhouski 我在发布自己的问题之前发现了这些问题;它很相似,但并没有真正让我满意。既然我在这里得到了回答,这些问题的答案就更有意义了。
  • @Damien_The_Unbeliever 有趣 - 谢谢!
  • “块”这个词与线程相关联。在这种情况下,您有一个异步工作流,而不是线程,因此为避免误解,您可以使用“暂停”一词。这是await 运算符文档中使用的词:await 运算符暂停对封闭异步方法的评估,直到其操作数表示的异步操作完成。

标签: c# .net .net-core async-await


【解决方案1】:

对Console.WriteLine的调用是否保证在ts中的任务等待后执行?

是的。

我想我见过在访问任务结果之前 await 似乎不会像那样“阻塞”的情况。

不,事实并非如此。您只会在等待操作符之后进入该语句(或者可能是语句中的下一个表达式within,例如,对于 (await a) + (await b),一旦等待的事情已经完成。

请注意,Task.WhenAll 本身并不是一个阻塞方法(与 Task.WaitAll 不同) - 但它返回的任务在作为参数传递的所有任务都完成之前不会完成。

【讨论】:

  • 我认为您在最后一句中省略了“not”(或者对于“Note”,您的意思是“Not”),这在一定程度上改变了语义。
  • 好的,谢谢。如果我有类似“await myC.Close(); await myC.Dispose();”之类的东西,同样适用在处理例如名为 myC 的类实例中的连接的方法中?想象一下按顺序调用它们很重要,即首先关闭,然后处置。那安全吗?
  • @ErikKinding:是的——尽管 Close() 和 Dispose() 听起来都不像异步方法。
【解决方案2】:

来自Task.WhenAll Method 文档:

创建一个将在所有提供的任务完成后完成的任务。

此页面上的第一个示例具有以下文本:

以下示例创建一组任务,用于对数组中的 URL 执行 ping 操作。任务存储在传递给 WhenAll(IEnumerable) 方法的 List 集合中。调用Wait方法后确保所有线程都已完成......

这意味着您的问题的答案是 - 只有在所有任务完成后才会调用Console.WriteLine

【讨论】:

    【解决方案3】:

    是的 - 你保证 Console.WriteLinets 中的所有任务都完成后执行,因为你 await 它。这记录在这里:https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall?view=netframework-4.8

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      • 2020-05-30
      • 1970-01-01
      • 2015-11-08
      相关资源
      最近更新 更多