运行时如何知道在使用“await”时何时生成线程

本文关键字:何时生 线程 await 何知道 运行时 | 更新日期: 2023-09-27 17:56:10

>编辑

我接受了乔恩的评论,并重新尝试了整个事情。事实上,它正在阻止 UI 线程。我一定以某种方式搞砸了我的初始测试。字符串"OnResume 退出"是在SomeAsync完成后写入的。如果将方法更改为使用await Task.WhenAll(t)则它(如预期的那样)不会阻止。感谢您的输入!我最初考虑删除这个问题,因为最初的假设是错误的,但我认为答案包含不应丢失的宝贵信息。

原帖:

试图理解异步等待的更深层次的内部结构。下面的示例来自使用 Xamarin 的 Android 应用。 OnResume()在 UI 线程上执行。

  • SomeAsync()启动一个新任务(= 它会生成一个线程)。然后它使用 Task.WaitAll() 来执行阻塞等待(我们现在不讨论WhenAll()是否是更好的选择)。
  • 我可以看到 UI 在运行时没有被阻止Task.WaitAll()。因此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);
}

运行时如何知道在使用“await”时何时生成线程

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

我想你会发现这个线程很有趣:C# 5.0 的 async-await 功能与 TPL 有何不同?

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

它所做的只是将代码"拆分"为放置"await"的行,以及该行作为延续添加到任务的所有内容。

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

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

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