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

我对在ASP中使用异步操作有一些担忧。净MVC。什么时候它提高我的应用程序的性能,什么时候它?

  1. 在 ASP.net MVC 中到处使用异步操作好吗?
  2. 关于可等待方法:当我想查询数据库(通过 EF/NHibernate/其他ORM ) 时,我应该使用 async/await 关键字吗?
  3. 我可以在一个 action 的 method 中使用 await 关键字异步查询数据库多少次 ?
131770 次浏览

async动作在动作对DB或网络绑定调用执行一些I\O操作时帮助最大,在这些操作中,处理请求的线程将在从你刚刚调用的DB或网络绑定调用获得应答之前被暂停。最好使用await,它将真正提高应用程序的响应性(因为在等待DB或其他类似操作时,ASP输入/输出线程将被暂停的情况更少)。在我所有的应用程序中,每当许多调用DB非常必要时,我总是将它们包装在可等待的方法中,并使用await关键字调用。

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

AsyncController类的典型用途是长时间运行的Web 服务调用。< / p >

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

IIS线程池通常可以处理比数据库服务器更多的并发阻塞请求。如果数据库是瓶颈,异步调用将不会加快数据库响应。在没有节流机制的情况下,通过使用异步调用将更多的工作高效地分配到不堪重负的数据库服务器,只会将更多的负担转移到数据库。如果您的DB是瓶颈,异步调用将不是灵丹妙药。

应该可以看看12引用

源自@PanagiotisKanavos评论:

此外,async并不意味着并行。异步执行释放 有价值的线程池线程从阻塞外部资源,为 没有复杂性或性能成本。这意味着同一台IIS机器可以 处理更多并发请求,并不是说它会运行得更快 你还应该考虑阻塞以a开头的调用 cpu密集型spinwait。在压力大的时候,阻止电话会 导致不断升级的延迟和应用程序池回收。异步调用 简单地避免这个

在ASP中处处使用异步操作好吗?净MVC吗?

像在编程中一样,它取决于。在走某条路的时候总是要权衡取舍的。

async-await在你知道你的服务将收到并发请求并且你希望能够很好地向外扩展的地方表现出色。async-await如何帮助向外扩展?事实上,当你调用异步IO调用同步时,例如网络调用或命中数据库,负责执行的当前线程将被阻塞,等待请求完成。当你使用async-await时,你让框架为你创建一个状态机,以确保在IO调用完成后,你的方法继续从它停止的地方执行。

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

使用async-await时要考虑的另一件事是它是完全异步,这意味着你会看到async从头到尾贯穿整个调用堆栈。这意味着如果你想公开同步API,你会经常发现自己重复了一定数量的代码,因为异步同步不能很好地混合在一起。

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

如果你选择使用异步IO调用,那么是的,async-await将是一个不错的选择,因为越来越多的现代数据库提供者公开了实现TAP(任务异步模式)的异步方法。

我可以使用await关键字查询数据库的次数 异步在一个单一的行动方法?< / p >

只要您遵守数据库提供商规定的规则,您想要多少就有多少。异步调用的数量没有限制。如果你的查询是相互独立的,并且可以并发执行,你可以为每个查询旋转一个新任务,并使用await Task.WhenAll来等待两个查询都完成。

如你所知,MVC支持异步控制器,你应该利用它。如果你的Controller执行了一个长时间的操作(可能是基于磁盘的I/o或对另一个远程服务的网络调用),如果以同步方式处理请求,IIS线程将一直处于繁忙状态。因此,线程只是等待冗长的操作完成。当第一个请求的操作正在进行时,可以更好地利用它为其他请求提供服务。这将有助于服务更多的并发请求。 你的webservice将是高度可伸缩的,不会轻易碰到C10k问题。 对db查询使用async/await是个好主意。是的,你可以使用它们的次数,只要你认为合适。

看看在这里的优秀建议。

你可以找到我的MSDN上关于这个主题的文章很有帮助;我在那篇文章中花了很多篇幅来描述当你应该在ASP上使用async。NET,而不仅仅是如何在ASP.NET上使用async

我对在ASP中使用异步操作有一些担忧。净MVC。什么时候它能提高我的应用程序的性能,什么时候呢?

首先,要理解async/await是关于释放线程的。在GUI应用程序上,它主要是关于释放GUI线程,因此用户体验更好。在服务器应用程序(包括ASP。NET MVC),它主要是关于释放请求线程,所以服务器可以伸缩。

特别地,它不会:

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

第一个问题是——在ASP中处处使用异步操作好吗?净MVC吗?

我想说,在I/O的任何地方都使用它是很好的。它可能不一定是有益的(见下文)。

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

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

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

注意,我说的是“you 可以 use”。如果你说的是ASP。使用一个数据库后端。NET MVC,那么你(几乎可以肯定)不会从async中获得任何可伸缩性的好处。这是因为IIS可以处理比单个SQL server(或其他经典RDBMS)实例多得多的并发请求。然而,如果你的后端更现代——一个SQL server集群,Azure SQL, NoSQL等——并且你的后端可以扩展,而你的可伸缩性瓶颈是IIS,你可以从async中获得可伸缩性的好处。

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

你想要多少都可以。但是,请注意,许多orm具有每个连接一个操作的规则。特别地,EF只允许每个DbContext执行单个操作;无论操作是同步的还是异步的,都是如此。

另外,请再次记住后端的可伸缩性。如果您正在使用单个SQLServer实例,并且您的IIS已经能够保持SQLServer的最大容量,那么对SQLServer施加两倍或三倍的压力根本不会对您有任何帮助。

我的5美分:

  1. 当且仅当你做IO操作时使用async/await,比如DB或外部服务webservice。
  2. 总是选择异步调用而不是DB。
  3. 每次查询DB时。

附注:第一点有例外情况,但你需要很好地理解异步内部。

作为一个额外的优势,如果需要,你可以并行执行很少的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

在ASP中处处使用异步操作好吗?净MVC吗?

在任何可以使用异步方法的地方这样做都是很好的,特别是当你在工作进程级别有性能问题时,这发生在大量数据和计算操作中。否则,不需要,因为单元测试将需要强制转换。

关于可等待方法:我是否应该使用async/await关键字当我 想查询一个数据库(通过EF/NHibernate/其他ORM)?< / p >

是的,对于任何DB操作最好使用异步,以尽可能避免工作进程级别的性能问题。 注意EF已经为大多数操作创建了许多异步替代,例如:

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

使用await关键字查询数据库的次数 异步在一个单一的动作方法?< / p >

前途无量

我的经验是,今天很多开发人员使用async/await作为控制器的默认值。

我的建议是只有当你知道它对你有帮助时才使用它

原因是,正如斯蒂芬·克利里和其他已经提到的,它会引入性能问题,而不是解决它们,并且它只会在特定的场景中帮助你:

  • 高流量控制器
  • 可伸缩的后端