什么时候应该在ASP.NET MVC中使用asynchronous控制器?

我有一些担心在ASP.NET MVC中使用asynchronous操作。 它什么时候提高了我的应用程序的性能,什么时候没有

  1. 在ASP.NET MVC中处处使用asynchronous动作是否好?
  2. 关于等待的方法:当我想查询一个数据库时(通过EF / NHibernate /其他ORM),我应该使用asynchronous/等待关键字?
  3. 可以使用多less次等待关键字来在一个单一的操作方法中asynchronous查询数据库?

当动作必须执行多个独立的长时间运行操作时, asynchronous操作方法非常有用。

AsyncController类的一个典型用途是长时间运行的Web服务调用。

我的数据库调用应该是asynchronous的?

IIS线程池通常可以处理比数据库服务器更多的同时阻塞请求。 如果数据库是瓶颈,asynchronous调用不会加快数据库响应速度。 没有限制机制,通过asynchronous调用有效地向更多的数据库服务器分配更多的工作只会将更多的负担转嫁给数据库。 如果你的数据库是瓶颈,asynchronous调用将不会是魔术。

应该看看1和2的引用

来自@PanagiotisKanavos评论:

而且,asynchronous并不意味着并行。 asynchronous执行释放一个有价值的线程池线程阻塞外部资源,没有复杂性或性能成本。 这意味着相同的IIS机器可以处理更多的并发请求,而不是运行得更快。

你也应该考虑阻塞调用从CPU密集型的spinwait开始。 在压力时期,阻止通话将导致延迟和应用程序池回收的升级。 asynchronous调用只是避免这种情况

你可能会发现我的MSDN文章对这个主题很有帮助 。 在那篇文章中,我花了很多篇幅来描述何时应该在ASP.NET上使用async ,而不仅仅是如何在ASP.NET上使用async

我有一些担心在ASP.NET MVC中使用asynchronous操作。 当它改善我的应用程序的性能,以及什么时候 – 没有。

首先,明白async / await是关于释放线程 。 在GUI应用程序中,主要是释放GUI线程,以便用户体验更好。 在服务器应用程序(包括ASP.NET MVC)上,主要是释放请求线程,以便服务器可以扩展。

特别是,它不会:

  • 使您的个人请求更快完成。 事实上,他们会完成(只是一点点)慢一点。
  • 当你await时,返回给调用者/浏览器。 只await “收益”到ASP.NET线程池,而不是浏览器。

第一个问题是 – 在ASP.NET MVC中处处使用asynchronous动作是否好?

我会说在你做I / O的地方使用它是很好的。 虽然(见下文),但未必有益

但是,将其用于CPU绑定方法是不好的 。 有时开发人员认为他们可以通过在其控制器中调用Task.Run来获得async的好处,这是一个可怕的想法。 因为代码最终通过占用另一个线程来释放请求线程,所以根本没有任何好处(事实上,他们正在考虑额外的线程切换)。

当我想查询数据库(通过EF / NHibernate /其他ORM)时,我应该使用asynchronous/等待关键字?

你可以使用任何可用的方法。 现在大多数主要玩家都支持async ,但是有一些不支持async 。 如果您的ORM不支持async ,那么不要试图将其封装在Task.Run或类似的东西(见上文)。

请注意,我说“你可以使用”。 如果你正在谈论的ASP.NET MVC单一数据库后端,那么你(几乎肯定)不会从async获得任何可伸缩性的好处。 这是因为IIS可以处理比单个SQL服务器(或其他传统的RDBMS)更多的并发请求。 但是,如果您的后端更现代化 – SQL服务器群集,Azure SQL,NoSQL等,并且您的后端可以扩展,并且您的可伸缩性瓶颈是IIS, 那么您可以从async获得可伸缩性。

第三个问题 – 我可以使用多less次等待关键字在一个单独的操作方法中asynchronous查询数据库?

尽可能多的你喜欢。 但是,请注意,许多ORM具有单操作每个连接规则。 特别是,EF只允许每个DbContext执行一个操作; 无论操作是同步的还是asynchronous的,都是如此。

另外请记住您的后端的可扩展性。 如果你碰到一个单一的SQL Server实例,并且你的IIS已经能够保持SQLServer的满负荷运行,那么把SQLServer的压力翻倍或者三倍并不会对你有所帮助。

在ASP.NET MVC中使用asynchronous动作是否好?

像往常一样在编程,这取决于 。 沿着一定的路线往往会有一个折衷。

async-await闪耀在你知道你会收到并发请求到你的服务的地方,你希望能够很好地扩展 。 如何async-await帮助扩大? 事实上,当你同步调用一个asynchronous的IO调用,比如networking调用或者触发你的数据库时,负责执行的当前线程被阻塞,等待请求完成。 当你使用async-await ,你可以让框架为你创build一个状态机,确保IO调用完成后,你的方法继续执行。

需要注意的是这个状态机有一个微妙的开销。 使一个asynchronous方法不会使它更快执行 ,这是一个很重要的因素,也是很多人误解的一个重要因素。

在使用async-await时需要考虑的另一件事情是,它一路asynchronous的 ,这意味着你会看到asynchronous渗透你的整个调用堆栈,从顶层到底层。 这意味着如果你想公开同步API,你会经常发现自己复制了一定数量的代码,因为asynchronous和同步混合不好。

当我想查询数据库(通过EF / NHibernate /其他ORM)时,我应该使用asynchronous/等待关键字?

如果您select使用asynchronousIO调用的path,那么是的, async-await将是一个不错的select,因为越来越多的现代数据库提供程序公开实现TAP(任务asynchronous模式)的asynchronous方法。

我可以使用多less次等待关键字在一个单一的动作方法中asynchronous查询数据库?

只要您遵循数据库提供商提供的规则,就可以随心所欲。 您可以进行asynchronous调用的数量没有限制。 如果你有查询是相互独立的,可以同时进行,你可以为每一个新的任务,并使用await Task.WhenAll等待两个完成。

当操作对数据库或某些networking绑定调用执行一些I \ O操作时, async操作最有助于处理请求的线程在从刚刚调用的数据库或networking绑定调用获得答案之前停止。 最好使用它们来等待,这样可以提高应用程序的响应速度(因为在等待数据库或其他类似的操作时,ASPinput/输出线程的数量会减less)。 在我所有的应用程序中,每次调用数据库都非常必要,我总是用awaoatable方法包装它们,并用await关键字调用它。

我的5美分:

  1. 当且仅当您执行IO操作(如数据库或外部服务Web服务)时才使用async/await
  2. 始终偏好对数据库的asynchronous调用。
  3. 每次查询数据库。

PS第1点有特殊的情况,但是你需要对这个asynchronous内部有一个很好的理解。

作为一个额外的好处,如果需要的话,可以并行执行less量IO调用:

 Task task1 = FooAsync(); // launch it, but don't wait for result Task task2 = BarAsync(); // launch bar; now both foo and bar are running await Task.WhenAll(task1, task2); // this is better in regard to exception handling // use task1.Result, task2.Result 

如你所知,MVC支持asynchronous控制器,你应该利用它。 如果您的控制器执行冗长的操作(可能是基于磁盘的I / O或者对另一个远程服务的networking调用),如果请求以同步方式处理,IIS线程将一直处于忙碌状态。 因此,线程正在等待冗长的操作完成。 在首先要求的操作正在进行的同时,通过服务其他请求可以更好地利用它。 这将有助于服务更多的并发请求。 你的web服务将是高度可扩展的,不会轻易碰到C10k的问题 。 db查询使用async / await是一个好主意。 是的,你可以使用他们尽可能多的次数,你认为合适的。

看看这里的优秀build议。