C# webapi中的异步调用
在asp.net Web API中,如何异步调用长时间运行的阻塞操作 我有一个web api控制器操作,它需要进行一个相对长(例如10秒)的运行DB调用。这似乎是异步方法的候选方法。我可以将长时间运行的任务卸载到新线程上,并取消阻止我的asp.net请求线程以处理其他一些请求,因此我简化的控制器操作如下所示:C# webapi中的异步调用,c#,asynchronous,asp.net-web-api,C#,Asynchronous,Asp.net Web Api,在asp.net Web API中,如何异步调用长时间运行的阻塞操作 我有一个web api控制器操作,它需要进行一个相对长(例如10秒)的运行DB调用。这似乎是异步方法的候选方法。我可以将长时间运行的任务卸载到新线程上,并取消阻止我的asp.net请求线程以处理其他一些请求,因此我简化的控制器操作如下所示: public async Task<IHttpActionResult> Get() { IEnumerable<Thing> things = await
public async Task<IHttpActionResult> Get()
{
IEnumerable<Thing> things = await Task.Run(() => DoLongDbCall());
return Ok(things);
}
公共异步任务Get()
{
IEnumerable things=wait Task.Run(()=>DoLongDbCall());
返回Ok(事物);
}
我遇到过一些博客(,例如)认为这可能不是在asp.net中实现这一点的最佳方式。作者建议使用Task.FromResult()
并同步执行DB调用,但我看不出这有什么帮助;我的请求线程仍将被阻止,等待DB调用返回
我的请求线程仍将被阻止,等待DB调用返回
这并不完全正确:
您的请求仍将等待长时间操作结束,但您的线程将可以自由处理其他操作
您必须记住,IIS的可用线程数量减少(特别是在非服务器系统下运行时),释放一个不需要的线程总是一件好事
此外,如果线程短缺,如果使用<代码>任务。运行< /COD>,异步操作将等待可用线程,如果不释放当前线程,则最终会出现一个可怕的死锁。
首先,考虑同步调用时发生的情况:
public IHttpActionResult Get()
{
IEnumerable<Thing> things = DoLongDbCall();
return Ok(things);
}
一个请求进入,ASP.NET抓取一个线程池线程来处理该请求。该线程调用Get
方法,然后该方法抓取另一个线程池线程来执行工作,并将原始线程池线程返回到线程池。一个线程池线程在整个请求期间使用(两个线程池线程在非常短的时间内使用)
因此,Task.Run
代码强制执行额外的线程转换,而不提供任何好处(在服务器端使用async
的全部目的是释放线程)。这就是为什么我建议不要在ASP.NET上使用Task.Run
(或以任何其他方式在线程池上运行工作)
适当的异步解决方案是使用异步DB调用:
public async Task<IHttpActionResult> Get()
{
IEnumerable<Thing> things = await DoLongDbCallAsync();
return Ok(things);
}
公共异步任务Get()
{
IEnumerable things=wait DoLongDbCallAsync();
返回Ok(事物);
}
一个请求进入,ASP.NET抓取一个线程池线程来处理该请求。该线程调用
Get
方法,该方法随后启动异步操作并将线程池线程返回到线程池。稍后,当db调用完成时,ASP.NET会抓取一个线程池线程来完成请求。对于大多数请求,不使用线程池线程(一个线程池线程在请求开始和结束时的一段短时间内使用)。所有请求都已在单独的线程上执行,因此,除非您希望并行执行两个或多个调用,否则不需要考虑阻塞。调用await Task.Run
只会在可以使用原始线程的情况下浪费另一个线程。您意识到在这种情况下,使用async
/await
真的没有什么好处吗?ADO.NET和EF确实支持异步调用DoLongDbCall
本身应该是一个异步方法。在这种情况下,您将在等待数据库时释放当前线程,而不使用额外的线程等待,这在某种程度上是有意义的,但我看不出Task.Run(()=>LongAction)
和LongActionAsync
之间的区别。不管我在它上面放了多少层抽象,我的“异步”在某个时候都需要创建一个新线程?@richzilla:不,它不一定需要单独的线程。我在我的博客上解释。这解释得太好了,我要尽快奖励一笔赏金。谢谢你,伙计。
public async Task<IHttpActionResult> Get()
{
IEnumerable<Thing> things = await DoLongDbCallAsync();
return Ok(things);
}