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

sol*_*ljy 2 asp.net asynchronous background async-await

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

void async Task LongWork()
{
    await LONGWORK() // ... long work 
}
Run Code Online (Sandbox Code Playgroud)

现在,在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";
   }
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!

Ste*_*ary 10

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

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

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

您没有提供任何选项.首先,他们都使用Task.Factory.StartNew而没有指定TaskScheduler,这是危险的(正如我在我的博客上所描述的那样).他们应该使用Task.Run.但是,即使您使用Task.Run,也会遇到更严重的潜在问题.

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

我在博客上更详细地描述了这个问题.此博客文章中还有一种类型BackgroundTaskManager,它使用ASP.NET运行时注册后台任务,并(通过)正确执行它们Task.Run.您应该只BackgroundTaskManager在阅读博客文章时理解并接受这仍然是危险且不安全的.

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