Async \ Await方法

时间:2016-04-22 10:25:17

标签: c# .net asynchronous

我是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堆栈时(因为我进入死亡日志)。

如果有人知道为什么会这样,我会很高兴。

4 个答案:

答案 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会为线程管理创建一个开销,这可能会导致您的操作执行得更慢。

相反,有两个主要优点:

  1. 使用async / await时,不会阻止该线程。这意味着当您的应用程序正在等待其他内容(例如IO,DB或webservice调用)时,该线程可以用于其他内容,例如执行我们请求的其他内容。这并不意味着DB调用将更快地执行。但它会让线程在等待时做其他事情。如果您使用IIS,则线程数量有限。因此,不是用昂贵的IO锁定它们,而是在等待时提供另一个请求。

  2. 您可以同时做更多事情。例如,您可以向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;
    }
    

    }

  3. 所以,总结一下。您应该使用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);
}