我应该使用等待异步Action方法吗?

我需要在我的Controller中实现一个异步Action,用于长时间运行的外部API调用。

看一些教程,我已经实现了我的方法:

[AsyncTimeout(200)] public async Task DoAsync() { // Execute long running call. return View(); } 

我的问题是,这足以使真正的非块异步吗? 我是否还需要应用await运算符,如果是,我该怎么做?

我需要在我的Controller中实现一个异步Action,用于长时间运行的外部API调用。

我的问题是,这足以使真正的非块异步吗? 我是否还需要应用await运算符,如果是,我该怎么做?

C#编译器可能已经建议async关键字在这里是多余的:

 [AsyncTimeout(200)] public async Task DoAsync() { // Execute long running call. return View(); } 

您添加了async关键字的事实并未使您的方法在后台神奇地运行。

如果您按照另一个答案的建议执行类似await Task.Run(() => View()) ,您仍然不会突破给定HTTP请求的边界。 请求处理将至少花费相同的时间来生成View而不使用Task.Run 。 客户端浏览器仍将等待它。

当您需要将CPU绑定的工作卸载到池线程时,此模式适用于UI应用程序,以避免阻止UI线程并保持UI响应。 但是,在ASP.NET应用程序内的HTTP请求处理程序中使用它几乎不是一个好主意。 它只会损害性能和可扩展性。

一个解决方案,提供用户友好的体验,以便在View花费大量时间撰写时, 运行跨越单个HTTP请求边界的后台任务 。 然后进一步使用AJAX请求来保持客户端浏览器的进度更新。 这是Alan D. Jackson的一个很好的例子,就是这样:

Asp.Net MVC3中的长时间运行后台任务 。

但是,在同一ASP.NET服务器进程内跨多个HTTP请求运行冗长的后台操作并不是一个好主意。 虽然它相对容易实现,但这种方法可能会产生IIS可维护性,可伸缩性和安全性方面的问题。

对于单独的Windows / WCF服务 ,您可能会更好,这会暴露基于Task的API。 然后使用AJAX定期轮询WCF服务,使用ASP.NET MVC控制器的专用方法作为轮询调用的代理。

要编写非阻塞异步代码,您需要执行某种现有的非阻塞异步操作,例如Task.Delay()或异步网络或文件IO。

简而言之, await关键字消耗异步; 它不会创造它。

如果您没有任何实际的异步工作要做, await对您没有任何好处。

正如另一个人写的那样,你需要一个异步动作来等待它,使View()异步将它包装在Task.Run

 [AsyncTimeout(200)] public async Task DoAsync() { // Execute long running call. return await Task.Run(() => View()); } 

之后,此方法主要用于从其他异步函数或回调调用。

我的问题是,这足以使真正的非块异步吗? 我是否还需要应用await运算符,如果是,我该怎么做?

您应该在异步MVC操作中使用await关键字,原因如下:

  1. 如果您的操作更改了应用程序的状态(更新数据库等),则await关键字使您可以在外部服务失败的情况下回滚更改。 否则这可能导致状态不一致,因为用户不能只重放给定的异步操作,它只能重放整个动作。
  2. 托管环境(IIS)可能导致应用程序域因不同原因而卸载。 当它发生时,您的应用程序永远无法获得异步操作的结果。 在常规请求处理案例中,ASP.NET等待每个操作完成。 如果某些请求需要很长时间才能完成(并且超过关闭超时),ASP.NET将中止它们并发送失败响应。

这就是为什么你不应该既不使用async ,也不使用其他.NET异步技术,如TPL。 在这种情况下,使用WCF的自定义Windows服务是一种更好的解决方案,但它使编程,部署和维护任务变得非常复杂。

当然,你可以使用HostingEnvironment.RegisterObject ,这里有一篇很好的文章 。 但是当ASP.NET调用IRegisteredObject接口实现的Stop方法时(在关闭期间),您只有30秒(默认情况下)保存数据。 如果您有未完成的异步操作,则应中止它们,将它们标记为失败并在重新启动后重试它们或向用户发送失败通知。 如果您的存储空间目前也不可用,请告知您的结果(包括失败的结果)。

您还可以使用持久队列,可靠的提取以及在ASP.NET应用程序中侦听这些队列的专用工作程序。 即使工作进程终止,这也可以保护您。 此外,还有很多项目,如Resque , Sidekiq , Pyres等,但它们适用于其他语言。

对于.NET,尝试一下HangFire – 它正在开发中,但是比这些系统的初始实现更稳定,并且具有许多不同的function。