4

根据这篇文章 ASP.NET 要求在控制器中使用相同SynchronizationContext的异步操作,否则它会阻塞正在运行的线程。作为结论,作者提到我们应该使用这两种方法作为防止线程死锁的最佳实践:

  1. 在您的“库”异步方法中,尽可能使用 ConfigureAwait(false)。
  2. 不要阻塞任务;一直使用异步。

    注意:最好同时应用这两种最佳实践。任何一种都可以防止死锁,但必须同时应用这两种方法以实现最大的性能和响应能力。

但是是什么目的导致微软使用相同的SynchronizationContext呢?可能使用ConfigureAwait(false)禁用相同同步上下文限制的 ,可能会导致不可预知的行为或性能问题。因此,在任何可能的地方使用 真的是一种好习惯ConfigureAwait(false)吗?

4

2 回答 2

3

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.ResultTask.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;

你认为应该发生什么?在等待之后更新文本框对您来说更自然,还是因为您现在不在原始上下文中而失败?

于 2015-03-01T11:34:01.100 回答
2

ASP.NET 要求在控制器中对异步操作使用相同的 SynchronizationContext,否则会阻塞正在运行的线程。

有点,但不完全是。ASP.NET 为每个传入请求创建一个SynchronizationContext,并且此上下文根本不绑定到特定线程。但是,一次只有一个线程可以进入上下文,因此如果第二个线程尝试进入上下文,而其中一个线程已经在其中,那么它将阻塞该线程。

什么目的导致微软使用相同的 SynchronizationContext?

for ASP.NET 管理每个请求的SynchronizationContext数据,例如HttpContext.Current文化和用户身份。

尽可能使用 ConfigureAwait(false) 真的很好吗?

作为一般规则,是的,尤其是对于通用库。在 ASP.NET 上,ConfigureAwait(false)不会给您带来太多好处 - 在某些情况下,性能会略有提高。它可以用来避免我在文章中提到的死锁,但是一直使用它要好得多(尤其是在 ASP.NET 上)async

于 2015-03-02T21:35:48.057 回答