簡體   English   中英

異步\\等待方法

[英]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,操作就不會更快地執行,相反。 異步/等待會增加線程管理的開銷,這可能會導致您的操作執行速度變慢。

相反,有兩個主要優點:

  1. 使用異步/等待時,您將不會阻塞線程。 這意味着當您的應用程序正在等待其他內容(例如IO,DB或Webservice調用)時,線程可以用於其他內容,例如執行我們請求的其他內容。 這並不意味着將更快地執行數據庫調用。 但是它會讓線程在等待時做其他事情。 如果您使用的是IIS,則線程數是有限的。 因此,與其在昂貴的IO上鎖定它們,不如在等待時為另一個請求提供服務。

  2. 您可以同時做更多的事情。 例如,您可以向數據庫發送請求,同時執行緩慢的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM