17

正如标题所暗示的,我的问题是关于“异步”和“等待”的背景。

说当前线程到达'await'关键字,它进入“睡眠”,并在await方法完成时唤醒是真的吗?

谢谢!

盖伊

4

3 回答 3

30

说当前线程到达'await'关键字,它进入“睡眠”,并在await方法完成时唤醒是真的吗?

不,关键async是要避免线程在可以做其他工作时休眠。此外,如果运行 async 方法的线程是 UI 线程,那么您根本不希望它处于休眠状态 - 您希望它可用于其他事件。

当执行到达一个await表达式时,生成的代码将检查您正在等待的东西是否已经可用。如果是,您可以使用它并继续前进。否则,它将在“等待”部分添加一个延续,并立即返回

延续确保在等待值准备好时运行其余的异步方法。发生在哪个线程取决于您正在等待的上下文 - 如果异步方法在线程池线程中运行,则延续可以在与方法启动的线程不同的线程上运行......但这不应该事情。(上下文的其余部分仍将被传播。)

请注意,异步方法可以在没有完成的情况下返回 - 因为异步方法不能直接返回值 - 它总是返回一个Task<T>(或Task,或void)......并且该方法返回的任务只会被完成当异步方法真正结束时。

于 2012-09-01T13:02:23.590 回答
3

不,当前线程实际上并没有进入睡眠状态。执行继续。这就是它的全部技巧。您可能有一些代码在异步操作仍处于挂起状态时处理数据。这意味着当这些异步完成时,您的主线程可以自由运行和处理其他数据。

至于问题的另一部分 - async 只是在另一个线程上执行,而不是当前线程。我相信 CLR 负责旋转这些线程,以便同时允许许多异步操作(即,您可能同时从不同的 Web 服务器异步检索数据)。

于 2012-09-01T13:02:58.143 回答
0

async只是允许await使用关键字的语法糖。

如果async, await在 ASP.NET Core 中使用,那么您的请求线程将被释放到线程池。

正如斯蒂芬·克利里所说:

异步请求处理程序的操作方式不同。当一个请求进来时,ASP.NET 获取它的一个线程池线程并将它分配给那个请求。这次请求处理程序将异步调用该外部资源。这会将请求线程返回到线程池,直到对外部资源的调用返回。图 3 说明了在请求异步等待外部资源时具有两个线程的线程池。

在此处输入图像描述

重要的区别是请求线程在异步调用进行时已经返回到线程池。当线程在线程池中时,它不再与该请求相关联。这一次,当外部资源调用返回时,ASP.NET 会采用其线程池线程之一并将其重新分配给该请求。该线程继续处理请求。当请求完成时,该线程再次返回到线程池。请注意,对于同步处理程序,同一线程用于请求的生命周期;相反,对于异步处理程序,不同的线程可能被分配给同一个请求(在不同的时间)。

对于桌面应用程序:

await释放当前线程,但不释放到线程池。UI 线程并非来自线程池。如果你运行异步方法,例如ExecuteScalarAsync没有async, await关键字,那么无论如何这个方法都会异步运行。调用线程不会受到影响。

特别感谢对Panagiotis Kanavos的好评。

例如,您有一个繁重的存储过程,而您的存储过程需要 10 分钟才能执行。如果您在没有async, await关键字的情况下从 C# 运行此代码,那么您的执行线程将等待您的存储过程 10 分钟。而这个等待线程什么也不做,它只会等待存储过程。

但是,如果async, await使用关键字,那么您的线程将不会等待存储过程。该线程将有资格工作。

于 2021-11-18T06:18:24.190 回答