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

Vnu*_*uuk 202 c# asp.net asynchronous async-await asp.net-mvc-4

我有一些担心在ASP.NET MVC中使用异步操作.当它提高了我的应用程序的性能,并且在做它不是

  1. 在ASP.NET MVC中使用异步操作是否合适?
  2. 关于等待方法:当我想查询数据库时(通过EF/NHibernate /其他ORM),我应该使用async/await关键字吗?
  3. 我可以使用await关键字在一个动作方法中异步查询数据库多少次?

Ste*_*ary 218

您可能会发现关于该主题的MSDN文章很有帮助 ; 我在该文章中占用了大量空间,描述了何时应该async在ASP.NET上使用,而不仅仅是如何async在ASP.NET 上使用.

我有一些担心在ASP.NET MVC中使用异步操作.当它提高我的应用程序的性能,以及何时 - 不是.

首先,要了解async/ await是关于释放线程的全部内容.在GUI应用程序上,它主要是释放GUI线程,以便用户体验更好.在服务器应用程序(包括ASP.NET MVC)上,它主要是释放请求线程,以便服务器可以扩展.

特别是,它不会:

  • 使您的个人请求更快完成.事实上,他们将完成(只是一点点)慢.
  • 当你点击时返回到来电/浏览器await.await只有"产生"到ASP.NET线程池,而不是浏览器.

第一个问题是 - 在ASP.NET MVC中到处使用异步操作是否合适?

我说在你做I/O的任何地方都可以使用它.但这可能不一定有益(见下文).

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

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

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

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

第三个问题 - 我可以使用等待关键字在一个单一操作方法中异步查询数据库的次数?

尽你所愿.但是,请注意,许多ORM具有每操作一个操作规则.特别是,EF只允许每个DbContext进行一次操作; 无论操作是同步还是异步,都是如此.

另外,请记住后端的可扩展性.如果您正在使用SQL Server的单个实例,并且您的IIS已经能够使SQLServer保持满负荷运行,那么SQLServer的压力加倍或增加三倍根本不会对您有所帮助.

  • @seebiscuit:执行(适当的异步)I/O时,不使用任何线程.我有一篇更详细的[博客文章](http://blog.stephencleary.com/2013/11/there-is-no-thread.html). (2认同)
  • IIS和单个SQL Server实例可以处理多少个请求?我怎样才能找到这些数字? (2认同)

Tha*_*rif 100

当操作必须执行多个独立的长时间运行操作时,异步操作方法很有用.

AsyncController类的典型用法是长时间运行的Web服务调用.

我的数据库调用应该是异步的吗

IIS线程池通常可以处理比数据库服务器更多的同时阻塞请求.如果数据库是瓶颈,异步调用将不会加速数据库响应.如果没有限制机制,通过使用异步调用有效地将更多工作分配给不堪重负的数据库服务器,只会将更多的负担转移到数据库.如果您的数据库是瓶颈,异步调用将不是神奇的子弹.

应该看看12个引用

源于@PanagiotisKanavos评论:

而且,异步并不意味着并行.异步执行使得有价值的线程池线程免于阻塞外部资源,因为没有复杂性或性能成本.这意味着相同的IIS计算机可以处理更多并发请求,而不是它将运行得更快.

您还应该考虑阻塞调用以CPU密集型spinwait开始.在压力期间,阻止呼叫将导致延迟和应用程序池回收不断升级.异步调用只是避免这种情况

  • 而且,异步并不意味着并行.异步执行使得有价值的线程池线程免于阻塞外部资源,因为没有复杂性或性能成本.这意味着*相同的IIS机器*可以处理*更多*并发请求,而不是它将运行得更快. (29认同)
  • 关于异步,IIS和数据库,博客文章非常陈旧,这里得出的结论是错误的.IIS必须服务器*比数据库更大的负载,线程池线程是有限的,长的请求队列可以导致500.任何在等待IO时释放线程的东西都是有益的.甚至链接都不是*关于OP所要求的.实际上,同一作者已经写过,你应该*尽可能地使用异步数据库方法 (27认同)
  • 您还应该考虑阻塞调用以CPU密集型spinwait开始.在压力期间,阻止呼叫将导致延迟和应用程序池回收不断升级.异步调用只是避免这种情况 (5认同)
  • 谢谢@PanagiotisKanavos分享您的意见. (2认同)

Yuv*_*kov 20

在ASP.NET MVC中使用异步操作是否很好?

像编程一样,它取决于.沿着某条路走下去时总会有一个权衡.

async-await在你知道你将收到并发请求服务的地方闪耀,你希望能够很好地扩展.如何async-await帮助扩展?事实上,当您同步调用异步IO调用(例如网络调用或命中数据库)时,将阻止负责执行的当前线程等待请求完成.使用时async-await,启用框架为您创建状态机,确保在IO调用完成后,您的方法从中断处继续执行.

需要注意的是,这个状态机有一个微妙的开销.使方法异步并不会使它执行得更快,这是一个重要的理解因素和许多人的误解.

在使用时需要考虑的另一件事async-await是它一直是异步的,这意味着你会看到异步穿透你的整个调用堆栈,从顶部到底部.这意味着如果您想要公开同步API,您通常会发现自己复制了一定数量的代码,因为异步同步不能很好地混合.

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

如果您选择沿着使用异步IO调用的路径前进,那么是的,async-await将是一个不错的选择,因为越来越多的现代数据库提供程序公开了实现TAP(任务异步模式)的异步方法.

有多少次我可以使用await关键字在一个单一动作方法中异步查询数据库?

只要您遵循数据库提供商声明的规则,就可以随心所欲.您可以进行异步调用的数量没有限制.如果您的查询彼此独立且可以同时进行,则可以为每个查询创建一个新任务,并await Task.WhenAll等待两者都完成.

  • 异步数据库调用执行速度不快,但允许相同的IIS计算机为更多请求提供服务,因为不会浪费线程池线程.它还降低了CPU成本,因为阻塞调用实际上是在实际阻塞之前以CPU密集型spinwait开始的.在高负荷情况下,这可能是机器挣扎或失效和回收之间的差异 (2认同)

boh*_*nko 7

我的5美分:

  1. 使用async/await当且仅当你做一个IO操作,如数据库或外部服务web服务.
  2. 总是喜欢对DB的异步调用.
  3. 每次查询数据库.

PS第1点有例外情况,但您需要对异步内部有很好的理解.

另外一个优点是,如果需要,您可以并行执行少量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
Run Code Online (Sandbox Code Playgroud)


Dim*_*tri 6

async当动作对数据库或某些网络绑定调用执行某些操作时,操作会有所帮助,其中处理请求的线程在从您刚刚调用的数据库或网络绑定调用中获得应答之前将被停止.你最好使用等待它们,它将真正提高你的应用程序的响应能力(因为在等待数据库或任何其他类似的操作时,较少的ASP输入\输出线程将被停止).在我的所有应用程序中,每当多次调用DB非常必要时,我总是将它们包装在可用的方法中并使用await关键字调用它.


小智 5

如您所知,MVC 支持异步控制器,您应该利用它。如果您的控制器执行一个冗长的操作(它可能是基于磁盘的 I/O 或对另一个远程服务的网络调用),如果以同步方式处理请求,则 IIS 线程一直很忙。结果,线程只是在等待冗长的操作完成。在第一个请求的操作正在进行时,通过为其他请求提供服务可以更好地利用它。这将有助于处理更多并发请求。您的网络服务将是高度可扩展的,不会轻易遇到C10k 问题。对数据库查询使用 async/await 是个好主意。是的,您可以根据需要多次使用它们。

看看这里以获得出色的建议。