我是Async / Await功能的新手,我试图在我的MVC项目中使用它们。
所以从Controller我调用当前方法来初始化我的模型:
var model = this.quantService.GetIndexViewModel(companyIds, isMore, currentrole).Result;
在这个GetIndexViewModel中,我使用await
:
public async Task<CompanyBoardViewModel> GetIndexViewModel(IEnumerable<int> parameter, bool isMore = false, bool currentRole = false)
{
return new CompanyBoardViewModel
{
TopJoinAplicant = await this.TopJointApplicant(parameter, isMore),
TopPriorityCountry = await this.TopPriorityCountry(parameter),
TopPublicationCountries = await this.TopPublicationCountries(parameter),
TopGrantedInventors = await this.TopGrantedInventors(parameter),
TopIPC = await this.TopIPC(parameter),
TopCPC = await this.TopCPC(parameter),
TopCitedInventors = await this.TopCitedInventors(parameter),
TopCitedPatents = await this.TopCitedPatents(parameter),
CGAR = await this.GetCGAR(parameter),
};
}
对于第一种方法,我使用这些代码:
private async Task<QuantTableViewModel<TopFilterViewModel>> TopJointApplicant(IEnumerable<int> ids, bool isMore = false)
{
return await Task.Run(() => new QuantTableViewModel<TopFilterViewModel>
{
Tableid = "TopJointApplicants",
Title = "Top Joint Applicants",
FirstCol = "Position",
SecondCol = "Joint Applicant",
ThirdCol = "#",
IsSeeMore = isMore,
Data = this.cache.TopJointApplicant(ids).ToList()
});
}
在这种方法中,我打电话给:Data = this.cache.TopJointApplicant(ids).ToList()
这个方法创建了一个过程并从数据库中获取信息(该方法执行没有任何问题),但是当我尝试返回QuantTableViewModel<TopFilterViewModel>
I堆栈时(因为我进入死亡日志)。
如果有人知道为什么会这样,我会很高兴。
答案 0 :(得分:2)
我解释了你在博客上看到的僵局。简而言之,don't block on async code;相反,请使用async all the way。
但您的方法还存在其他问题。正如其他人所说,await Task.Run
是ASP.NET上的反模式。您可能想在async ASP.NET上阅读我的文章。
最后,另一个提示:你正在从错误的方向接近问题。您应该首先考虑应用程序正在做什么,并开始将I / O调用转换为最低级别的异步 ,而不是仅选择“异步”方法。将它们转换为使用异步API而不是阻止API(即,不Task.Run
)。然后将其调用者更改为异步,并将其调用者更改为异步,最终将控制器方法更改为异步。
答案 1 :(得分:0)
使用async / await模式时,不需要使用Task.Run。
答案 2 :(得分:0)
在这种情况下,我会说你的公共方法是异步的,因为在TopJointApplicant中并没有真正发生异步。
public async Task<CompanyBoardViewModel> GetIndexViewModel(IEnumerable<int> parameter, bool isMore = false, bool currentRole = false)
{
return new CompanyBoardViewModel
{
TopJoinAplicant = this.TopJointApplicant(parameter, isMore),
TopPriorityCountry = await this.TopPriorityCountry(parameter),
TopPublicationCountries = await this.TopPublicationCountries(parameter),
TopGrantedInventors = await this.TopGrantedInventors(parameter),
TopIPC = await this.TopIPC(parameter),
TopCPC = await this.TopCPC(parameter),
TopCitedInventors = await this.TopCitedInventors(parameter),
TopCitedPatents = await this.TopCitedPatents(parameter),
CGAR = await this.GetCGAR(parameter),
};
}
private QuantTableViewModel<TopFilterViewModel> TopJointApplicant(IEnumerable<int> ids, bool isMore = false)
{
var Data = this.cache.TopJointApplicant(ids).ToList();
return new QuantTableViewModel<TopFilterViewModel>
{
Tableid = "TopJointApplicants",
Title = "Top Joint Applicants",
FirstCol = "Position",
SecondCol = "Joint Applicant",
ThirdCol = "#",
IsSeeMore = isMore,
Data = this.cache.TopJointApplicant(ids).ToList()
});
}
如果您要使用它,我建议您完全接受await / async-pattern。这意味着您的控制器也应该使用await / async。
public class YourController : Controller
{
// Note the Task<ActionResult> and async in your controller.
public async Task<ActionResult> YourControllerMethod()
{
var model = await this.quantService.GetIndexViewModel(companyIds, isMore, currentrole);
return View(model); // Or something like this.
}
}
另外,请考虑您的命名约定。为清楚起见,异步方法应以后缀Async结尾,例如GetIndexViewModelAsync
。
编辑: 根据评论,我认为我应该澄清await / async的作用。操作不会因为使用await / async-pattern而执行速度更快,而是相反。 Async / await会为线程管理创建一个开销,这可能会导致您的操作执行得更慢。
相反,有两个主要优点:
使用async / await时,不会阻止该线程。这意味着当您的应用程序正在等待其他内容(例如IO,DB或webservice调用)时,该线程可以用于其他内容,例如执行我们请求的其他内容。这并不意味着DB调用将更快地执行。但它会让线程在等待时做其他事情。如果您使用IIS,则线程数量有限。因此,不是用昂贵的IO锁定它们,而是在等待时提供另一个请求。
您可以同时做更多事情。例如,您可以向DB发送请求,同时执行慢速Web服务调用。这可能会导致总执行时间更快,因为您可以同时执行更多操作。但是,有一些限制。例如,如果您正在使用实体框架,则当时只有一个线程可以访问上下文。但在等待数据库时,您可以做其他事情。例如:
public class MyThreadingClass
{
private Task ExecuteWebServiceCallAsync()
{
return await _myService.DoSomething();
}
private Task ExecuteDbQueryAsync()
{
return await _context.Customer.FirstOrDefaultAsync();
}
public void DoThingsWithWaitAll()
{
var tasks = new Task[2];
// Fire up first task.
tasks[0] = ExecuteWebServiceCallAsync();
// Fire up next task.
tasks[1] = ExecuteDbQueryAsync();
// Wait for all tasks.
Task.WaitAll(tasks);
}
public Task DoThingsWithWithAwaitAsync()
{
// Fire up first task.
var webServiceTask = ExecuteWebServiceCallAsync();
// Fire up next task.
var dbTask = ExecuteDbQueryAsync();
// Wait for all tasks.
await webServiceTask;
await dbTask;
}
}
所以,总结一下。您应该使用await / async的原因是当您可以执行所有方式执行慢速操作(例如DB或webservice)时。或者如果你想一次做几件事。
在您的特定情况下,您可以执行以下操作:
public async Task<CompanyBoardViewModel> GetIndexViewModel(IEnumerable<int> parameter, bool isMore = false, bool currentRole = false)
{
// Let the threads start processing.
var topApplicantTask = this.TopJointApplicant(parameter, isMore);
var topPriorityCountryTask = this.TopPriorityCountry(parameter);
var topPublicationContriesTask = this.TopPublicationCountries(parameter);
var topIPCTask = this.TopIPC(parameter);
var topCPCTask = this.TopCPC(parameter);
var topCitedInventorsTask = this.TopCitedInventors(parameter);
var topCitetPatentsTask = this.TopCitedPatents(parameter);
var getCGARTask = this.GetCGAR(parameter);
// Await them later.
return new CompanyBoardViewModel
{
TopJoinAplicant = await topApplicantTask,
TopPriorityCountry = await topPriorityCountryTask,
TopPublicationCountries = await topPublicationContriesTask,
TopGrantedInventors = await this.TopGrantedInventors(parameter),
TopIPC = await topIPCTask,
TopCPC = await topCPCTask,
TopCitedInventors = await topCitedInventorsTask,
TopCitedPatents = await topCitetPatentsTask,
CGAR = await getCGARTask,
};
}
但是尽量避免使用Task.Run,因为它被认为是反模式。相反,尝试从控制器到实际操作(DB,IO,webservice)一直使用await / async。此外,在上面的示例中,还有很多线程正在进行中。它可能会被清理一下,但您可以将其视为概念验证,而不是建议的解决方案。
答案 3 :(得分:0)
您实际上可以拥有一个异步控制器,因此您无需调用.Result,它可以使异步操作同步运行。
类似的东西:
public Task<ActionResult> Index(object parameter)
{
var model = await this.quantService.GetIndexViewModel(companyIds, isMore, currentRole);
return View(model);
}