我有一个MVC控制器动作,它执行了许多步骤 像
Public ActionResult Index()
{
GetDatFromTabelCustomer()
GetDataFromWebApi()
GetDataFromSession()
GetyetAnotherData()
SendItToView()
}
我打算用Task.Run
包装每个方法
然后在我处理之前Task.WhenAll()
和SendItToView()
。但是有很多关于为什么不应该使用Task.Run的博客
而是做异步等待,在这种情况下我真的想要以串行方式运行并行任务而不是等待每一个,
在这样做时,从线程池中缝合和拆除线程会有一些成本,但我还有什么其他选择比做Task.Run?
示例
Public ActionResult Index()
{
Task taska = Task.Run(() => GetDatFromTabelCustomer())
Task taskb = Task.Run(() => GetDataFromWebApi())
Task taskc = Task.Run(() => GetDataFromSession())
Task taskd = Task.Run(() => GetyetAnotherData())
await taska;
await taskb;
await taskc;
await taskd;
string get resultA = taska.Result
.
.
.
SendItToView()
}
答案 0 :(得分:2)
你不应该使用Task.Run
。你想要的是并发(一次多件事),而不是 parallelism (同时在不同线程上有多个东西)。 Parallelism是一种并发形式,但您也可以使用Task.WhenAll
执行异步并发。
要正确解决这个问题,首先要从你的"离开"开始,即实际的数据库调用,WebAPI调用等。使这些端点异步(例如,使用EF的异步查询或HttpClient
),然后让async
从那里成长。最后,您最终会得到GetDataFromTableCustomerAsync
和GetDataFromWebApiAsync
方法,然后您可以在控制器方法中使用这些方法:
public async Task<ActionResult> Index()
{
var taska = GetDataFromTableCustomerAsync();
var taskb = GetDataFromWebApiAsync();
// Both the db query and WebAPI calls are in progress at this point.
// So do anything *synchronous* that you want to do.
// For example, reading session data is not I/O-bound; it should just be done synchronously.
var sessionData = GetDataFromSession();
// Now, (asynchronously) wait for all the asynchronous work to complete.
await Task.WhenAll(taska, taskb);
// And get the results.
var resultA = await taska;
var resultB = await taskb;
SendItToView();
}
答案 1 :(得分:1)
&#34;正确&#34;这样做的方法是将你的函数重写为异步而不是重写为异步,你可以将Task.Run()用于那些不公开异步API的函数。您还可以使用Task.WhenAll(
将所有任务合并到一个等待的东西中。
public async Task<ActionResult> IndexAsync()
{
Task<string> taska = GetDatFromTabelCustomerAsync());
Task taskb = GetDataFromWebApiAsync());
Task taskc = Task.Run( () => GetDataFromSession());
Task taskd = Task.Run( () => GetyetAnotherData());
await Task.WhenAll(taska, taskb, taskc, taskd);
string resultA = await taska;
SendItToView()
}
在您的示例中,您显示taska
返回一个字符串,我修复了代码来执行此操作。第二次在任务上调用await
是免费的,而且调用taska.Result
是一个更好的习惯,你绝不应该从异步方法中做.Result
。
Here is a good article解释如何从同步MVC代码转换为异步MVC代码
答案 2 :(得分:0)
那些似乎都是IO密集型操作,所以我怀疑使用Task.Run()真的不是这里的方法。但是,您仍然可以使用Task.WhenAll()。您的每个方法都必须返回一个Task,并且可能会使用异步模式来完成它们的工作。然后,做这样的事情:
var tasks = new List<Task>()
tasks.Add(GetDataFromTableCustomer());
tasks.Add(GetDataFromWebApi());
...
await Task.WhenAll(tasks);
此外,由于这些方法返回Task,因此最好使用Async对其名称进行后缀。