修改
我接受了Jon的评论并重新审视了整个事情。事实上, 阻止了UI线程。我必须以某种方式弄乱我的初步测试。字符串“OnResume exits”在 SomeAsync
完成后写为。如果方法更改为使用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);
}
答案 0 :(得分:6)
简单:从不为await
生成一个主题。如果等待已经完成,它就会继续运行;如果等待不已完成,它只是告诉等待实例添加 continuation (通过一个相当复杂的状态机)。当正在完成的事情完成时,将调用continuation(通常通过sync-context,如果有的话 - 在标记工作完成的线程上同步)。然而!理论上,sync-context可以选择将事物推送到线程池(大多数UI同步上下文,但是,将内容推送到UI线程)。
答案 1 :(得分:1)
我想你会发现这个帖子很有趣:How does C# 5.0's async-await feature differ from the TPL?
简而言之,await
不会启动任何线程。
它做了什么,只是将代码“拆分”到了“await”放置的位置,以及将该行添加为 continuation 的所有内容。的任务强>
注意任务。请注意,您已获得Factory.StartNew
。因此,在您的代码中,工厂实际上启动任务 - 它包括将其放在某个线程上,无论是UI还是池还是任何其他任务调度程序。这意味着,当您执行等待时,“任务”通常已经分配到某个调度程序。
当然,它不必分配,也不必开始。唯一重要的是你需要有一个任务,真的。
如果未启动任务 - await不关心。它只是附加延续,由您决定以后启动任务。并将其分配给适当的调度程序。