Answers:
当一个动作必须执行几个独立的长时间运行的操作时,异步动作方法很有用。
AsyncController类的典型用法是长时间运行的Web服务调用。
我的数据库调用应该异步吗?
IIS线程池通常可以比数据库服务器处理更多的同时阻止请求。如果数据库是瓶颈,异步调用将不会加快数据库响应速度。如果没有限制机制,则通过使用异步调用有效地将更多工作分配给不堪重负的数据库服务器,只会将更多的负担转移到数据库上。如果您的数据库是瓶颈,那么异步调用将不是魔术。
来自@PanagiotisKanavos评论:
而且,异步并不意味着并行。异步执行使宝贵的线程池线程免于阻塞外部资源,而没有任何复杂性或性能成本。这意味着同一台IIS机器可以处理更多的并发请求,而不是运行得更快。
您还应该考虑到阻塞调用始于占用大量CPU的Spinwait。在压力时期,阻止调用将导致延迟升级和应用程序池回收。异步调用只是避免这种情况
您可能会发现有关该主题的我的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 Server群集,Azure SQL,NoSQL等-并且后端可以扩展,并且可伸缩性瓶颈是IIS,那么您可以从中获得可伸缩性async
。
第三个问题-我可以使用一次单一操作方法中的await关键字异步查询数据库多少次?
随你喜欢。但是,请注意,许多ORM都有“每个连接一个操作”的规则。尤其是,EF仅允许每个DbContext执行单个操作。无论操作是同步还是异步,都是如此。
此外,请再次记住后端的可伸缩性。如果您遇到的是SQL Server的单个实例,并且您的IIS已经能够使SQLServer保持满负荷运行,那么对SQLServer施加的压力加倍或增加三倍将完全无济于事。
在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
来等待两个查询完成。
scale out well
意思your server won't die under load
。或者可能是once burned ...
我的5美分:
async/await
当且仅当你做一个IO操作,如数据库或外部服务web服务。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
我的经验是,如今许多开发人员都将async/await
其用作控制器的默认设置。
我的建议是,只有在您知道它会帮助您时才使用它。
原因是,正如Stephen Cleary和其他人已经提到的那样,它可能会引入性能问题,而不是解决它们,并且仅在特定情况下会为您提供帮助:
在ASP.NET MVC的任何地方使用异步操作是否很好?
最好在任何可以使用异步方法的地方执行此操作,尤其是当您在工作进程级别出现性能问题时(发生在海量数据和计算操作中)。否则,不需要,因为单元测试将需要转换。
关于等待方法:当我要查询数据库时(通过EF / NHibernate /其他ORM),我应该使用async / await关键字吗?
是的,最好对所有数据库操作都使用异步,以避免在工作进程级别出现性能问题。请注意,EF为大多数操作创建了许多异步替代方法,例如:
.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()
一个单一的操作方法可以使用await关键字异步查询数据库多少次?
天空才是极限