简体   繁体   English

在 'async' 方法上到达 'await' 时线程会发生什么?

[英]What happens to the thread when reaching 'await' on 'async' method?

My question as the title suggest is about the background of 'async' and 'await'.正如标题所暗示的那样,我的问题是关于“异步”和“等待”的背景。

Is it true to say that what the current thread reaches 'await' keyword, it goes to "sleep", and wakes up when the await method is done?是不是说当前线程到达 'await' 关键字,就进入“睡眠”状态,等待方法完成后唤醒?

Thanks!谢谢!

Guy盖伊

Is it true to say that what the current thread reaches 'await' keyword, it goes to "sleep", and wakes up when the await method is done? 说当前线程到达'await'关键字是什么,它会进入“休眠”,并在await方法完成时唤醒,这是真的吗?

No. The whole point of async is to avoid having threads sleeping when they could be doing other work. 不。 async的全部意义在于,当他们可以做其他工作时避免让线程处于休眠状态。 Additionally, if the thread running the async method is a UI thread, you really don't want it to be sleeping at all - you want it to be available to other events. 另外,如果运行async方法的线程是一个UI线程,那么你真的不希望它在休眠 - 你希望它可用于其他事件。

When execution reaches an await expression, the generated code will check whether the thing you're awaiting is already available. 当执行到达await表达式时,生成的代码将检查您正在等待的事物是否已经可用。 If it is, you can use it and keep going. 如果是,你可以使用它并继续前进。 Otherwise, it will add a continuation to the "awaitable" part, and return immediately . 否则,它将为“等待”部分添加延续并立即返回

The continuation makes sure that the rest of the async method gets run when the awaitable value is ready. 继续确保在等待值准备好时运行异步方法的其余部分。 Which thread that happens in depends on the context in which you're awaiting - if the async method is running in thread pool threads, the continuation could run on a different thread to the one the method started on... but that shouldn't matter. 发生在哪个线程取决于您正在等待的上下文 - 如果异步方法在线程池线程中运行,则延续可以在与该方法启动的线程不同的线程上运行...但是不应该物。 (The rest of the context will still be propagated.) (其余的上下文仍将传播。)

Note that it's fine for the async method to return without having completed - because an async method can't return a value directly - it always returns a Task<T> (or Task , or void )... and the task returned by the method will be only be completed when the async method has really reached the end. 请注意,async方法在没有完成的情况下返回是很好的 - 因为异步方法不能直接返回值 - 它总是返回一个Task<T> (或Task ,或void )...并且返回的任务由只有当异步方法真正到达终点时才会完成方法。

No. Current thread actually doesn't go to sleep. 不。当前线程实际上不会进入睡眠状态。 The execution continues. 执行继续。 This is the whole trick of it. 这是它的全部技巧。 You may have some code that processes data while asynchronous actions are still pending. 您可能有一些代码处理数据,而异步操作仍处于待处理状态。 It means that by the time those async completes your main thread is free to run and process other data. 这意味着当异步完成时,您的主线程可以自由运行并处理其他数据。

As for the other part of the question - async just executes on another thread, not the current one. 至于问题的另一部分 - 异步只是在另一个线程上执行,而不是当前线程。 I believe that CLR is responsible for spinning those threads, so that many async actions are allowed at the same time (ie you may be retrieving data asynchronously from different web servers at the same time). 我相信CLR负责旋转这些线程,因此允许同时执行许多异步操作(即,您可能同时从不同的Web服务器异步检索数据)。

async is only syntactic sugar that allows await keyword to be used. async只是允许使用await关键字的语法糖。

If async, await is used in ASP.NET Core, then your request thread will be released to thread pool.如果在 ASP.NET Core 中使用了async, await ,那么您的请求线程将被释放到线程池中。

As Stephen Cleary says: 正如斯蒂芬·克利里所说:

Asynchronous request handlers operate differently.异步请求处理程序的操作方式不同。 When a request comes in, ASP.NET takes one of its thread pool threads and assigns it to that request.当一个请求进来时,ASP.NET 使用它的一个线程池线程并将它分配给那个请求。 This time the request handler will call that external resource asynchronously.这次请求处理程序将异步调用该外部资源。 This returns the request thread to the thread pool until the call to the external resource returns.这会将请求线程返回到线程池,直到对外部资源的调用返回。 Figure 3 illustrates the thread pool with two threads while the request is asynchronously waiting for the external resource.图 3 说明了在请求异步等待外部资源时具有两个线程的线程池。

在此处输入图片说明

The important difference is that the request thread has been returned to the thread pool while the asynchronous call is in progress.重要的区别是请求线程在异步调用过程中已经返回到线程池中。 While the thread is in the thread pool, it's no longer associated with that request.当线程在线程池中时,它不再与该请求相关联。 This time, when the external resource call returns, ASP.NET takes one of its thread pool threads and reassigns it to that request.这一次,当外部资源调用返回时,ASP.NET 使用其线程池线程之一并将其重新分配给该请求。 That thread continues processing the request.该线程继续处理请求。 When the request is completed, that thread is again returned to the thread pool.当请求完成时,该线程再次返回到线程池。 Note that with synchronous handlers, the same thread is used for the lifetime of the request;请注意,对于同步处理程序,请求的生命周期使用相同的线程; with asynchronous handlers, in contrast, different threads may be assigned to the same request (at different times).相比之下,对于异步处理程序,不同的线程可能会分配给同一个请求(在不同的时间)。

For desktop application:对于桌面应用程序:

await releases the current thread, but NOT to the thread pool. await释放当前线程,但不会释放到线程池。 The UI thread doesn't come from the thread pool. UI 线程不是来自线程池。 If you run asynchronous method, eg ExecuteScalarAsync without async, await keywords, then this method will run asynchronously no matter what.如果您运行异步方法,例如ExecuteScalarAsync没有async, await关键字,那么无论如何该方法都将异步运行。 The calling thread won't be affected .调用线程不会受到影响。

Special thanks for nice comments to Panagiotis Kanavos .特别感谢Panagiotis Kanavos 的精彩评论。

Eg you have a heavy stored procedure and your stored procedure takes 10 minutes to be executed.例如,您有一个繁重的存储过程,并且您的存储过程需要 10 分钟才能执行。 And if you run this code from C# without async, await keywords, then your execution thread will wait your stored procedure for 10 minutes.如果您在没有async, await关键字的情况下从 C# 运行此代码,那么您的执行线程将等待您的存储过程 10 分钟。 And this waiting thread will do nothing, it will just wait stored procedure.而这个等待线程什么都不做,它只会等待存储过程。

However, if async, await keyword is used, then your thread will not wait stored procedure.但是,如果使用async, await关键字,则您的线程将不会等待存储过程。 The thread will be eligible to work.该线程将有资格工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM