【问题标题】:How does the runtime know when to spawn a thread when using "await"?使用“等待”时,运行时如何知道何时生成线程?
【发布时间】:2014-04-02 07:14:22
【问题描述】:

编辑

我接受了 Jon 的评论并重试了整个过程。事实上,它阻塞了 UI 线程。我一定以某种方式搞砸了我的初始测试。 SomeAsync 完成后写入字符串“OnResume exits”。如果方法更改为使用await Task.WhenAll(t),它将(如预期的那样)不会阻塞。感谢您的输入! 我最初考虑删除问题是因为最初的假设是错误的,但我认为答案包含不应丢失的有价值信息。

原帖:

试图了解 async-await 的更深层次的内部结构。下面的示例来自使用 Xamarin 的 Android 应用程序。 OnResume() 在 UI 线程上执行。

  • SomeAsync() 开始一个新任务(= 它产生一个线程)。然后它使用Task.WaitAll() 执行阻塞等待(我们现在不讨论WhenAll() 是否是更好的选择)。
  • 我可以看到,Task.WaitAll() 正在运行时 UI 没有被阻止。所以SomeAsync() 不会在 UI 线程上运行。这意味着创建了一个新线程。

await 是如何“知道”它必须在这里生成一个线程的——它会一直这样做吗?如果我将WaitAll() 更改为WhenAll(),就不需要像我理解的那样快的额外线程。

// This runs on the UI thread.
async override OnResume()
{
  // What happens here? Not necessarily a new thread I suppose. But what else?
  Console.WriteLine ("OnResume is about to call an async method.");
  await SomeAsync();

  // Here we are back on the current sync context, which is the UI thread.
  SomethingElse();
  Console.WriteLine ("OnResume exits");
}

Task<int> SomeAsync()
{
var t = Task.Factory.StartNew (() => {
    Console.WriteLine("Working really hard!");
    Thread.Sleep(10000);
    Console.WriteLine("Done working.");
});
Task.WhenAll (t);

return Task.FromResult (42);
}

【问题讨论】:

  • Task.WaitAll() 应该阻塞 UI 线程。您通常会使用 Task.WhenAll 异步等待。这可能是某些 Xamarin 特定的行为,或者您可能误诊。请注意,这不是您的真实代码 - 它不会编译,因为 OnResume 的方法声明无效并且 SomeAsync 既没有声明为 async 也没有返回任何内容。

标签: c# async-await


【解决方案1】:

简单:它从不await 生成线程。如果 awaitable 已经完成,它会继续运行;如果可等待对象完成,它只是告诉可等待实例添加一个延续(通过相当复杂的状态机)。当正在完成的事情完成时,将调用延续(通常通过同步上下文,如果有的话 - 否则在将工作标记为完成的线程上同步)。然而!理论上,同步上下文可以选择将事物推送到线程池(然而,大多数 UI 同步上下文会将事物推送到 UI 线程)。

【讨论】:

    【解决方案2】:

    我想你会觉得这个话题很有趣:How does C# 5.0's async-await feature differ from the TPL?

    简而言之,await 不会启动任何线程。

    它所做的只是将代码“拆分”到放置“等待”的行的位置,并将该行作为 continuation 添加到任务

    注意任务。请注意,您有Factory.StartNew。因此,在您的代码中,实际启动任务的是工厂 - 它包括将其放置在某个线程上,无论是 UI 还是池或任何其他任务调度程序。这意味着,当您执行等待时,“任务”通常已经分配给某个调度程序。

    当然,它不必分配,也不必启动。唯一重要的是你需要有一个任务,真的。

    如果任务未启动 - 等待无关紧要。它只是附加延续,稍后由您来启动任务。并将其分配给适当的调度程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      相关资源
      最近更新 更多