ASP.NET WebApi中的async / await在后台

时间:2013-10-02 22:40:51

标签: asp.net asynchronous background async-await

假设我有以下异步方法,需要相当长的时间才能完成其工作:

void async Task LongWork()
{
    await LONGWORK() // ... long work 
}

现在,在web api中,我想在后台运行该工作(即,我想在启动LongWork()之后但在完成之前返回Http请求:

我可以想到实现这个目标的三种方法:

1) public async Task<string> WebApi()
   {
       ... // do another work

       await Task.Factory.StartNew(() => LongWork());

       return "ok";
   }
2) public async Task<string> WebApi()
   {
       ... // do another work

       await Task.Factory.StartNew(async () => await LongWork());

       return "ok";
   }

3) public async Task<string> WebApi()
   {
       ... // do another work

       Task.Factory.StartNew(async () => await LongWork());

       return "ok";
   }

问题1:方法#1和#2之间有什么区别?

Q2:在ASP.NET世界中,运行方法(在此示例中,LongWork()在后台线程中包含一些异步/等待对的正确方法是什么? 特别是在#3中,在Task.Factory.StartNew(async()=&gt; await LongWork())之前没有“等待”。好吗?

谢谢!

1 个答案:

答案 0 :(得分:8)

  

问题1:方法#1和#2之间有什么区别?

#1的开销较小。这是唯一的区别。

  

Q2:在ASP.NET世界中,运行方法(在此示例中,LongWork()在后台线程中包含一些异步/等待对的正确方法是什么?

您提供的所有选项均不适用。首先,他们都是use Task.Factory.StartNew without specifying a TaskScheduler, which is dangerous(正如我在博客中描述的那样)。他们应该使用Task.Run代替。但是,即使您使用Task.Run,也会遇到更严重的潜在问题。

基本问题是:HTTP协议以每个请求为中心,只有一个匹配的响应。当HTTP服务器(例如ASP.NET)知道没有未完成的请求时,它会做出“回收工作进程是安全的”假设。

I describe this problem in more detail on my blog。此博客文章中还有一个类型BackgroundTaskManager,它使用ASP.NET运行时注册后台任务,并通过Task.Run(正确)执行它们。 如果您阅读博客文章并理解并接受这仍然存在危险且不安全,则应该只使用BackgroundTaskManager

更好(读取:更可靠)的解决方案是首先写出要对持久存储(例如,Azure队列)执行的工作的表示,并且具有独立的后端进程(例如,Azure工作者角色)处理来自队列的请求。