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

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


当前回答

As you know, MVC supports asynchronous controllers and you should take advantage of it. In case your Controller, performs a lengthy operation, (it might be a disk based I/o or a network call to another remote service), if the request is handled in synchronous manner, the IIS thread is busy the whole time. As a result, the thread is just waiting for the lengthy operation to complete. It can be better utilized by serving other requests while the operation requested in first is under progress. This will help in serving more concurrent requests. Your webservice will be highly scalable and will not easily run into C10k problem. It is a good idea to use async/await for db queries. and yes you can use them as many number of times as you deem fit.

看看这里的优秀建议。

其他回答

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

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

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

特别是,它不会:

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

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

我想说,在I/O的任何地方都使用它是很好的。不过,这未必是有益的(见下文)。

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

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

您可以使用任何可用的可等待方法。现在大多数主流游戏都支持异步,但也有少数不支持。如果你的ORM不支持异步,那么不要尝试将它包装在Task中。运行或类似的操作(参见上面)。

Note that I said "you could use". If you're talking about ASP.NET MVC with a single database backend, then you're (almost certainly) not going to get any scalability benefit from async. This is because IIS can handle far more concurrent requests than a single instance of SQL server (or other classic RDBMS). However, if your backend is more modern - a SQL server cluster, Azure SQL, NoSQL, etc - and your backend can scale, and your scalability bottleneck is IIS, then you can get a scalability benefit from async.

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

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

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

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

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

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

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

你应该看一下第一和第二篇参考文献

源自@PanagiotisKanavos评论:

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

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

在编程中,这要视情况而定。在走某条路的时候总是要权衡取舍的。

async-await shines in places where you know you'll receiving concurrent requests to your service and you want to be able to scale out well. How does async-await help with scaling out? In the fact that when you invoke a async IO call synchronously, such as a network call or hitting your database, the current thread which is responsible for the execution is blocked waiting for the request to finish. When you use async-await, you enable the framework to create a state machine for you which makes sure that after the IO call is complete, your method continues executing from where it left off.

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

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

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

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

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

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

async actions help best when the actions does some I\O operations to DB or some network bound calls where the thread that processes the request will be stalled before it gets answer from the DB or network bound call which you just invoked. It's best you use await with them and it will really improve the responsiveness of your application (because less ASP input\output threads will be stalled while waiting for the DB or any other operation like that). In all my applications whenever many calls to DB very necessary I've always wrapped them in awaiatable method and called that with await keyword.

我的5美分:

当且仅当你做IO操作时使用async/await,比如DB或外部服务webservice。 总是选择异步调用而不是DB。 每次查询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