[英]Async\Await methods
我是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>
我堆疊(當我進入死亡日志時)。
如果有人知道為什么會發生,我將非常高興。
我解釋了您在博客上看到的僵局。 簡而言之, 不要阻塞異步代碼 ; 相反,請一路使用async 。
但是您的方法還有其他問題。 正如其他人指出的那樣, await Task.Run
是ASP.NET上的反模式。 您可能需要閱讀我關於異步ASP.NET的文章。
最后,另一個提示:您正在從錯誤的方向解決問題。 您不僅應該選擇一種方法來“使異步”,還應該首先考慮您的應用程序在做什么,然后開始將最低級別的 I / O調用轉換為異步。 將它們轉換為使用異步API而不是阻止API(即,沒有Task.Run
)。 然后將其調用者更改為異步,並將其調用者更改為異步,最終將您的控制器方法更改為異步。
使用異步/等待模式時,無需使用Task.Run。
在這種情況下,我要說的是,您的公共方法是異步的就足夠了,因為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,操作就不會更快地執行,相反。 異步/等待會增加線程管理的開銷,這可能會導致您的操作執行速度變慢。
相反,有兩個主要優點:
使用異步/等待時,您將不會阻塞線程。 這意味着當您的應用程序正在等待其他內容(例如IO,DB或Webservice調用)時,線程可以用於其他內容,例如執行我們請求的其他內容。 這並不意味着將更快地執行數據庫調用。 但是它會讓線程在等待時做其他事情。 如果您使用的是IIS,則線程數是有限的。 因此,與其在昂貴的IO上鎖定它們,不如在等待時為另一個請求提供服務。
您可以同時做更多的事情。 例如,您可以向數據庫發送請求,同時執行緩慢的Web服務調用。 這可能會導致總執行時間更快,因為您要同時執行更多操作。 但是,有局限性。 例如,如果您使用的是Entity Framework,則此時只有一個線程可以訪問上下文。 但是,在等待數據庫時,您可以執行其他操作。 例如:
公共類MyThreadingClass {
私有任務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,Web服務)的整個過程中使用await / async。 另外,在上面的示例中,有很多線程在進行。 可能應該對其進行一些清理,但您可以將其視為概念證明,而不是建議的解決方案。
實際上,您可以有一個異步控制器,因此您無需調用.Result即可使異步操作同步運行。
就像是:
public Task<ActionResult> Index(object parameter)
{
var model = await this.quantService.GetIndexViewModel(companyIds, isMore, currentRole);
return View(model);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.