运行时如何知道在使用“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
生成线程。如果等待对象已经完成,它就会继续运行;如果 Awaitable 尚未完成,它只是告诉 Awaitable 实例添加延续(通过相当复杂的状态机)。当正在完成的事情完成时,这将调用延续(通常通过同步上下文,如果有的话 - 否则在将工作标记为完成的线程上同步)。然而!从理论上讲,同步上下文可以是选择将内容推送到线程池的上下文(但是,大多数 UI 同步上下文会将内容推送到 UI 线程)。
我想你会发现这个线程很有趣:C# 5.0 的 async-await 功能与 TPL 有何不同?
简而言之,await
不会启动任何线程。
它所做的只是将代码"拆分"为放置"await"的行,以及该行作为延续添加到任务的所有内容。
记下任务。请注意,您有Factory.StartNew
.因此,在您的代码中,实际启动任务的是工厂 - 它包括将其放置在某个线程上,无论是 UI 或池或任何其他任务计划程序。这意味着,当您执行 await 时,"任务"通常已经分配给某个调度程序。
当然,它不必分配,也不必开始。唯一重要的是你需要有一个任务,任何,真的。
如果任务未启动 - 等待不关心。它只是附加延续,由您稍后开始任务。并将其分配给适当的调度程序。