首页 > 解决方案 > C#。如果“等待之后”线程很忙,会发生什么?

问题描述

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

提前感谢您的回答。

标签: c#.netasynchronousasync-awaittask-parallel-library

解决方案


这取决于SynchronizationContext安排延续的线程。

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

所有这些只是部分正确,因为您可以通过调用返回的before ing来配置await调用以不捕获当前。SynchronizationContextConfigureAwait(false)Taskawait

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

TL;DR:你实际上问了一个相当简单的问题,但答案却非常复杂。简而言之:允许在任何线程上继续执行,除非SynchronizationContext强制它这样做。更详细地说,这个答案会变成一篇相当大的博客文章,比我聪明得多的人已经写过关于这个的博客文章,所以我只会将你链接到有关该主题的更多资源:

Stephen Toub 的常见问题解答ConfigureAwait

Stephen Cleary 的详细 MSDN 文章

Stephen Toub 的“Await、SynchronizationContext 和控制台应用程序”

Stephen Cleary 关于 ASP.NET Core SynchronizationContext

Stephen Cleary 的“不要阻塞异步代码”

SynchronizationContext 有什么作用?

为什么控制台应用程序中没有捕获默认的 SynchronizationContext?


推荐阅读