ASP.NET要求在控制器中使用相同的SynchronizationContext进行异步操作,否则会阻塞运行线程。
我不太确定这个陈述的意思。ASP.NET并不需要“相同”的同步上下文。为了让您在HttpContext
中,您需要那个SynchronizationContext
。
但是,微软使用相同的SynchronizationContext
有什么目的呢?
我建议您阅读It's All About SynchronizationContext,以便更好地了解同步上下文的大局。基本上,它是一种机制,允许您在特定线程上发布继续执行。例如,它可以用于将工作传回UI应用程序中的UI消息循环线程。
也许使用ConfigureAwait(false)会导致例如不可预测的行为或性能问题,因为它禁用了相同的同步上下文限制
相反地,将工作重新调度到同步上下文确实会有(非常小的)开销,因为请求需要使用抽象的
SynchronizationContext.Post
发布回所需的线程和上下文。通过使用
ConfigureAwait(false)
,您可以“节省”这些时间,并在分配任何线程上继续执行。
因此,无论何时可能,使用 ConfigureAwait(false) 确实是一个好习惯吗?
这样做的主要原因是避免死锁。当有人调用
Task.Result
或
Task.Wait
而不是使用
await
进行异步等待时,您会遇到经典的死锁场景,其中同步上下文正在尝试将继续返回到线程上,但它当前被阻塞,因为
Result
和
Wait
是阻塞调用。另一个原因是您得到的轻微性能开销。
编辑:
为什么 Microsoft 不将此方法封装在 Task 类中?看起来 ConfigureAwait(false) 只有优点。是否有任何缺点?
让我们想象以下场景:您执行一个返回
Task
的方法,并使用
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;
你认为应该发生什么?在等待后更新文本框更自然,还是因为不在原始上下文中而失败?这是问题。
async-await
的一般目的是简化异步编程并使其易于使用开发人员。 - Yuval Itzchakov