ASP.NET MVC中异步编程的最佳实践是什么?

时间:2015-03-01 10:11:38

标签: c# .net asp.net-mvc async-await synchronizationcontext

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

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

         

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

  4.   

但是什么目的导致微软使用相同的SynchronizationContext?可能正在使用禁用相同同步上下文限制的ConfigureAwait(false),可能导致例如不可预测的行为或性能问题。因此,在任何可能的地方使用ConfigureAwait(false)是否真的很好?

2 个答案:

答案 0 :(得分:3)

  

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

我不确定那句话是什么意思。 ASP.NET不需要“相同”的同步上下文。为了让您进入HttpContext,您需要SynchronizationContext

  

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

我建议您阅读It's All About SynchronizationContext以了解有关同步上下文的更多信息。基本上,它是一种允许您在特定线程上发布延续的机制。例如,它可以用于将工作编组回UI应用程序内的UI消息循环线程。

  

可能正在使用ConfigureAwait(false),它会禁用相同的配置   同步上下文限制,可能导致例如不可预知的行为或   绩效问题

恰恰相反。编组工作回到同步上下文确实有(非常小的)开销,因为需要将请求(使用抽象SynchronizationContext.Post)发布回所需的线程和上下文。通过使用ConfigureAwait(false),您保存该时间,并继续执行已分配线程的任务。

  

因此,使用ConfigureAwait(false)是否真的很好   哪里可能?

这样做的主要原因是避免死锁。当有人调用Task.ResultTask.Wait而不是使用await异步等待时,您会得到经典的死锁情况,其中同步上下文试图将延续回发到线程上,但它当前是阻止,因为ResultWait阻止了通话。另一个原因是您获得的性能开销很小。

编辑:

  

为什么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;

您认为应该怎么做?您是否更自然能够在等待之后更新文本框,或者因为您现在不在原始上下文中而失败?

答案 1 :(得分:2)

  

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

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

  

是什么目的导致Microsoft使用相同的SynchronizationContext?

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

  

在任何可能的地方使用ConfigureAwait(false)是否真的很好?

作为一般规则,是的,特别是对于通用库。在ASP.NET上,ConfigureAwait(false)对您没有多大帮助 - 在某些情况下,性能会有轻微提升。 可以用于避免我在文章中提到的死锁,但是一直使用async会更好(特别是在ASP.NET上)。