【发布时间】:2016-01-14 04:29:18
【问题描述】:
我的愿望是制作一个异步执行长时间运行的 i/o 操作的 MVC 控制器 Action。我的目标是避免在这个长时间运行的方法完成时占用 ASP.Net 线程池中的线程。
Action 进行了两次调用。
第一次调用是对不包含任何异步方法的第 3 方 dll。此 dll 从专有数据库中读取并执行相当复杂的 CPU 绑定处理。最多可能需要几秒钟才能返回。
第二次调用将第一次调用的结果作为参数传递给使用 Entity Framework 的数据库查询。
简单来说,这是动作:
public async Task<ActionResult> MyActionAsync(arg1, arg2)
{
var parameters = 3rdPartyComponent.TakesLongTime(arg1, arg2);
Task<List<MyClass>> genericList = null;
using (DbContexts.MyDbContext db = new DbContexts.MyDbContext())
{
genericList = await db.Database.SqlQuery<MyClass>(sql,parameters).ToListAsync();
}
return View("MyView", genericList);
}
我想让对 3rdPartyComponent 的调用可以等待。我最初的想法是这样做:
var parameters = await Task.Run(() => 3rdPartyComponent.TakesLongTime()).ConfigurateAwait(false);
但我读过几位主题专家明确指出,在 asp.net MVC Action 中使用 Task.Run() 会适得其反,永远不应该这样做。
3rdPartyComponent 是编译后代码的黑盒,无法更改以添加异步方法。
有什么方法可以让 3rdPartyComponent 的调用处于等待状态,这样整个 Action 就可以在不占用 asp.net 线程池中的线程的情况下运行?
【问题讨论】:
-
在 asp.net MVC Action 中的Task.Run() 会适得其反,永远不应该这样做。这不是真的。在很多情况下,您可能想要这样做。我并不是说你应该一直这样做,但如果你想生成一个单独的线程,那为什么不呢?
-
嘿汤姆,读一读这个:blog.stephencleary.com/2013/08/startnew-is-dangerous.html 并考虑你是否在优化方面为时过早......除非这是一种流量很大的方法,否则肯定有可能这是一个不必要的步骤。 (您可能最终会使用 Task.Factory.StartNew 以便您可以提供一个 TaskCreationOptions 以安排线程池之外的工作)
-
@spender,是的,这是一个大流量的方法,非常如此。
-
在这种情况下,使用线程是个坏主意。但这并不意味着永远不应该这样做。 Web 应用程序中的线程应该用于同时执行多个任务或作为触发和忘记线程。产生一个线程来完成主进程可以做的相同工作(当主线程等待时)会适得其反。您为同一任务使用了两倍的线程。我相信这就是他的观点。
-
缓存
3rdPartyComponent.TakesLongTime()的结果会不会更简单?