好吧,我想我几乎可以理解async / await
和多线程上的所有绒毛了。我知道异步与任务有关,多线程与工作人员有关。这样一来,您就可以在同一线程上运行不同的任务(this answer在解释它方面做得很好)。
所以我制作了一个小程序以查看魔术的发生,但我有些困惑:
public class Program
{
public static async Task Main(string[] args)
{
var task = ToastAsync();
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Cleaning the kitchen...");
await task;
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Take the toast");
}
public async static Task ToastAsync()
{
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Putting the toast");
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Setting a timer");
await Task.Delay(2000);
Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Toast is ready");
}
}
在第一次运行该程序之前,我希望它可以在单个线程上运行。就像我上面链接的答案一样,我希望这相当于“在烤面包机的计时器运行时打扫厨房”。结果虽然矛盾:
[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[4] Take the toast
上面的结果对我来说意义不大。到底发生了什么事?似乎该功能的一部分正在一个线程中执行,然后当它到达await
点时,它将执行权交给另一个线程...?我什至不知道这是可能的D:
此外,我对上面的示例进行了一些更改。在主函数中,我使用await task;
而不是task.Wait()
。然后结果改变了:
[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[1] Take the toast
现在,这看起来更像示例。就像烤面包机上的计时器充当了另一个“炊具”一样。但是,为什么与使用await
不同?有没有办法在单个线程中完全获取异步任务?我的意思是,在Toast is ready
上也有thread 1
吗?
感谢异步!
答案 0 :(得分:5)
需要注意的是
调用ToastAsync
时,它会启动 任务 热(即使您没有调用{{ 1}})。注意:启动任务并不意味着启动线程...这反过来解释了为什么要“清洁厨房”。在“放烤面包”的后面)
await
方法将一直运行到击中其第一个async
关键字为止,并将控制权交还给调用者。
由于控制台应用中没有await
。编译器认为无需在调用线程上创建 Continuation ,这反过来解释了为什么“ Take the toast”与“ Toast ready”在同一线程上
注意 :如果您在弄乱后打扫厨房,则不必事先打扫
来自评论
然后我知道,等待将始终从线程中获取线程 池运行该方法(这确实让我大吃一惊) 基本上不可能有一个异步/等待单线程
Asnyc and Await模式本身不是关于多线程的问题,而是关于可伸缩性和与IO绑定的工作负载和/或 UI 响应能力(在< em> UI 框架)
看看有关这个主题的 Stephen Cleary的博客
答案 1 :(得分:1)
如果您从Windows窗体事件中运行相同的代码,则会得到预期的结果:
[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[1] Toast is ready
[1] Take the toast
这是因为默认情况下,await
在等待之后恢复上下文,但是这样做是有代价的,因为这是一件额外的事情。如果不需要上下文还原,则可以这样配置await:
await Task.Delay(2000).ConfigureAwait(false);
...,您将看到与控制台应用程序相同的输出。
请记住,等待不是要同时执行操作,而是要使UI保持响应。您希望能够继续接收新的烤面包订单,而以前的订单正在烤面包。