C#.如果“等待后"会发生什么情况?线程忙吗? [英] C#. What happens if "after await" thread is busy?

查看:83
本文介绍了C#.如果“等待后"会发生什么情况?线程忙吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当等待的任务完成但启动异步方法的线程不可用(例如处理另一个请求)时,在C#中会发生什么?然后将使用另一个线程而不是第一个线程,或者执行将一直等到繁忙线程可用?

预先感谢您的回答.

解决方案

这取决于安排了继续的线程的 SynchronizationContext .

例如,当您在具有UI线程的应用程序(例如ASP.NET或WPF应用程序)中使用 async/await 时,在UI线程上安排的任何继续操作也将在UI线程.在控制台应用程序中,未捕获 SynchronizationContext ,默认行为是在必须恢复执行时在任何可用线程上执行.如果您想一想,实际上在任何"线程上执行比在安排继续的完全相同的线程上执行要容易得多.

所有这些仅部分正确,因为您可以通过调用 ConfigureAwait(false) await 调用以不捕获当前的 SynchronizationContext >在等待 之前返回的 Task 上.

为了说明这一点,请注意,如果您在ASP.NET应用程序中在UI线程上启动异步工作,然后强行阻止它直到完成工作(例如,通过调用 Task.Result),则您的代码可能会死锁.放在返回的 Task 上.现在,您有一个必须在UI线程上执行的延续,但是UI线程正在等待该延续执行,因此将永远不会继续执行.如果您在控制台应用程序中执行相同操作,并且线程池中有可用线程,则代码不会被阻塞,因为它可以在任何"线程上自由执行.调用 ConfigureAwait(false)后,在任何应用中都会发生相同的情况-因为不会捕获 SynchronizationContext .

TL; DR :您实际上已经问了一个相当简单的问题,答案非常复杂.简短地说一下:允许执行在任何线程上继续,除非 SynchronizationContext 强制它执行否则.进入更多细节会将这个答案变成相当大的博客文章,比我聪明得多的人已经撰写了有关此问题的博客文章,因此,我只将您链接到该主题的更多资源:

Stephen Toub关于 ConfigureAwait 的常见问题解答

Stephen Toub的"Await,SynchronizationContext和控制台应用程序"

Stephen Cleary关于ASP.NET Core SynchronizationContext

Stephen Cleary的请勿阻止异步代码"

SynchronizationContext做什么?

为什么未捕获默认SynchronizationContext在控制台应用程序中?

What happens in C# when awaitable task is finished but the thread in which async method had been started is unavailable (handles another request for example) ? Will then be used another thread instead of the first one, or execution will wait until the busy thread is available ?

Thanks in advance for your answers.

解决方案

That depends on the SynchronizationContext of the thread on which the continuation was scheduled.

For example, when you're using async/await in an app with a UI thread, like an ASP.NET or WPF app, any continuations scheduled on the UI thread will also execute on the UI thread. In a console app no SynchronizationContext is captured, and the default behaviour will be to execute on whatever thread is available when the execution has to resume. If you give it some thought, it's actually much easier to execute on a "whatever" thread than on the exact same that scheduled the continuation.

All of that is only partially true, because you can configure an await call to not capture the current SynchronizationContext by calling ConfigureAwait(false) on the returned Task before awaiting.

To illustrate that, note that your code can deadlock if in an ASP.NET app you start asynchronous work on the UI thread and then force it to block until that work is completed, for example by calling Task.Result on the returned Task. Now you have a continuation that has to execute on the UI thread, but the UI thread is waiting for that continuation to execute, so none will ever proceed. If you do the same in a console app and there are free threads in the threadpool, the code won't block, because it's free to execute on a "whatever" thread. The same will happen in any app after calling ConfigureAwait(false) - cause no SynchronizationContext will be captured.

TL;DR: You've actually asked a rather simple question that has a horribly complicated answer. To state it shortly: the execution is allowed to continue on any thread, unless the SynchronizationContext forces it to do otherwise. Going into more detail would turn this answer into a rather large blog post, and people much smarter than me have already produced blog posts about this, so I'll just link you to more sources on the topic:

Stephen Toub's FAQ about ConfigureAwait

Stephen Cleary's detailed MSDN article

Stephen Toub's "Await, SynchronizationContext, and Console Apps"

Stephen Cleary about ASP.NET Core SynchronizationContext

Stephen Cleary's "Don't Block on Async Code"

What does SynchronizationContext do?

Why the default SynchronizationContext is not captured in a Console App?

这篇关于C#.如果“等待后"会发生什么情况?线程忙吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆