ASP.NET 要求在控制器中对异步操作使用相同的 SynchronizationContext,否则会阻塞正在运行的线程。
我不太确定那句话是什么意思。ASP.NET 不需要“相同”的同步上下文。为了让你在你的内心HttpContext
,你需要那个SynchronizationContext
。
但是是什么目的导致微软使用相同的SynchronizationContext
呢?
我建议您阅读It's All About SynchronizationContext以了解有关同步上下文的更大图景。基本上,它是一种允许您在特定线程上发布延续的机制。例如,它可用于将工作编组回 UI 应用程序内的 UI 消息循环线程。
可能正在使用禁用相同同步上下文限制的 ConfigureAwait(false),可能会导致不可预知的行为或性能问题
相反。将工作重新编组到同步上下文确实有(非常小的)开销,因为需要将请求(使用 abstract SynchronizationContext.Post
)发布回所需的线程和上下文。通过使用ConfigureAwait(false)
,您可以节省时间并简单地继续执行已分配的线程。
因此,尽可能使用 ConfigureAwait(false) 真的是一种好习惯吗?
这样做的主要原因是避免死锁。当有人调用Task.Result
而Task.Wait
不是使用异步等待await
时,您会遇到经典的死锁场景,其中同步上下文试图将延续发布回线程,但它当前被阻塞,因为Result
并且Wait
正在阻塞调用。另一个原因是您获得的性能开销较小。
编辑:
为什么微软不把这个方法封装在Task类里面呢?看起来 ConfigureAwait(false) 只有优点。有什么缺点吗?
让我们想象一下以下场景:您执行一个返回 aTask
并等待使用的方法await
,然后立即更新一些 UI 元素。现在,什么对你来说更自然?您希望隐式返回到之前的相同“环境”(UI 线程),还是希望您必须明确指定要返回到相同的环境?
我认为前者对用户“感觉”更自然。
例子:
public Task FetchAndReturnAsync(string url)
{
var httpClient = new HttpClient();
return httpClient.GetAsync(url);
}
你这样称呼它:
var awesomeUiResult = await FetchAndReturnAsync("http://www.google.com");
textBox.Text = awesomeUiResult;
你认为应该发生什么?在等待之后更新文本框对您来说更自然,还是因为您现在不在原始上下文中而失败?