异步\等待方法
我是一个新的异步/等待功能,我试图在我的MVC项目中使用它们。异步等待方法
因此,从控制器我调用当前方法来初始化我的模型:
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()
此方法创建了一个过程并从数据库中获取信息(该方法没有任何问题地执行),但是当我尝试返回堆栈时(正如我在死亡日志中那样)时。
我会很开心,如果有人知道这是为什么发生。
使用异步/ AWAIT模式时,您不需要使用Task.Run。
我尝试没有Task.Run(),但我没有它收到的时间是一样的,因为我不使用await(所以逻辑是这样的不是异步) –
@KostadinPirgov - 我不知道你完全理解什么'异步“。 'await Task.Run()'是一种反模式,因为你所做的只是将某个活动移动到另一个线程,然后立即暂停当前线程的工作,直到结果可用。 –
在这种情况下,我会说这是它足以将自己的公开方法是异步的,因为有没有真正的任何asyncronous在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-pattern而更快地执行,而是相反。异步/等待为线程管理创建开销,这可能会导致您的操作执行速度变慢。
相反,有2个主要优点:
当使用异步/等待你不会阻塞线程。这意味着,当应用程序正在等待其他事情(例如IO,DB或Web服务调用)时,该线程可以用于其他事情,比如执行我们请求的其他事情。这并不意味着DB调用会更快执行。但它会让线程在等待时做其他事情。如果您使用的是IIS,则线程数量是有限的。因此,他们不用昂贵的IO来锁定它们,而是可以在等待时提供另一个请求。
-
您可以在同一时间做更多的事情。例如,您可以向DB发送请求,同时执行缓慢的Web服务调用。这可能会导致总执行时间更快,因为您在同一时间执行更多操作。但是,有一些限制。例如,如果您使用实体框架,那么当时只有一个线程可以访问上下文。但在等待数据库时,你可以做其他事情。例如:
公共类MyThreadingClass {
私人任务ExecuteWebServiceCallAsync(){ 回报 等待_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。另外,在上面的例子中,有很多线程正在进行。它可能会被清理一些,但你可以将它看作是一个概念验证,而不是建议的解决方案。
谢谢,我现在就试试吧! –
我试过了你的建议,但我收到的时间与我不使用异步/等待时相同。 –
一件事:我想在 公共执行方法异步任务
实际上你可以有一个异步控制器,所以你不需要调用.Result,它使异步操作同步运行。
类似:
public Task<ActionResult> Index(object parameter)
{
var model = await this.quantService.GetIndexViewModel(companyIds, isMore, currentRole);
return View(model);
}
我以这种方式尝试,它的工作,但我收到的时间是,当我没有异步/等待执行方法相同。 感谢您的建议。 –
我解释你在我的博客上看到了僵局。总之,don't block on async code;而是使用async all the way。
但您的方法还存在其他问题。正如其他人所指出的,await Task.Run
是ASP.NET上的反模式。你可能想阅读我的文章async ASP.NET。
最后,还有一个提示:你正从错误的方向接近问题。您应该首先考虑您的应用程序正在做什么,而不是仅选择一种方法来“制作异步”,而是开始将I/O调用转换为最低级别的异步。将它们转换为使用异步API而不是阻塞API(即没有0)。然后将其调用者更改为异步,并将他们的调用者更改为异步,最终将您的控制器方法更改为异步。
你可以提供适当格式的方法吗? –
@ÖmerCinbat - 我已经提交了一个编辑,目前正在等待同行评审。 – smoksnes
您对await + Task.Run的使用是毫无意义且实际有害的。我建议你研究*为什么和何时*异步是好的。 – usr