简体   繁体   English

异步\\等待方法

[英]Async\Await methods

I am a new in the Async/Await functionality and I tried to use them in my MVC project. 我是Async / Await功能的新手,我尝试在MVC项目中使用它们。

So from the Controller I call the current method to initialize my model: 所以从Controller我调用当前方法来初始化我的模型:

var model = this.quantService.GetIndexViewModel(companyIds, isMore, currentrole).Result;

In this GetIndexViewModel I use await : 在此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),
                };

}

For the first method I use these code: 对于第一种方法,我使用以下代码:

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()
            });
}

In this method I call : Data = this.cache.TopJointApplicant(ids).ToList() this method created a procedure and get information from the Database(the method is executed without any problems), but when I try to return the QuantTableViewModel<TopFilterViewModel> I stack(as I go in a death log). 在此方法中,我调用: Data = this.cache.TopJointApplicant(ids).ToList()此方法创建了一个过程并从数据库中获取信息(该方法执行时没有任何问题),但是当我尝试返回QuantTableViewModel<TopFilterViewModel>我堆叠(当我进入死亡日志时)。

I will be really happy if anyone know why this is happened. 如果有人知道为什么会发生,我将非常高兴。

I explain the deadlock you're seeing on my blog. 我解释了您在博客上看到的僵局。 In short, don't block on async code ; 简而言之, 不要阻塞异步代码 instead, use async all the way . 相反,请一路使用async

But there are other problems with your approach. 但是您的方法还有其他问题。 As others have noted, await Task.Run is an antipattern on ASP.NET. 正如其他人指出的那样, await Task.Run是ASP.NET上的反模式。 You may want to read my article on async ASP.NET . 您可能需要阅读我关于异步ASP.NET的文章。

Finally, one other tip: you're approaching the problem from the wrong direction. 最后,另一个提示:您正在从错误的方向解决问题。 Instead of just choosing a method to "make async", you should first think about what your application is doing, and start converting I/O calls to async at the lowest level . 您不仅应该选择一种方法来“使异步”,还应该首先考虑您的应用程序在做什么,然后开始将最低级别的 I / O调用转换为异步。 Convert them to use async APIs instead of blocking APIs (ie, no Task.Run ). 将它们转换为使用异步API而不是阻止API(即,没有Task.Run )。 Then change their callers to async, and their callers to async, eventually changing your controller method(s) to async. 然后将其调用者更改为异步,并将其调用者更改为异步,最终将您的控制器方法更改为异步。

使用异步/等待模式时,无需使用Task.Run。

In this case I would say that's it's enough that your public method is async, since there's not really any asyncronous going on in TopJointApplicant. 在这种情况下,我要说的是,您的公共方法是异步的就足够了,因为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()
                });
            }

I recommend you to fully embrace the await/async-pattern if you're going to use it. 如果您要使用它,建议您完全使用await / async-pattern。 This means that your controller also should use await/async. 这意味着您的控制器还应该使用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.
    }
}

Also, consider your naming convention. 另外,请考虑您的命名约定。 For clarity, async methods should end with the suffix Async, such as GetIndexViewModelAsync . 为了清楚起见,异步方法应以后缀Async结尾,例如GetIndexViewModelAsync

EDIT: Based on the comments I think I should clarify what await/async does. 编辑:根据评论,我想我应该澄清一下await / async的作用。 An operation will not execute faster simply because you use the await/async-pattern, rather the opposite. 仅仅因为您使用await / async-pattern,操作就不会更快地执行,相反。 Async/await creates an overhead for the thread management which would likely cause your operation to execute slower. 异步/等待会增加线程管理的开销,这可能会导致您的操作执行速度变慢。

Instead, there are 2 main advantages: 相反,有两个主要优点:

  1. When using async/await you will not block the thread. 使用异步/等待时,您将不会阻塞线程。 This means that while you're application is waiting for something else (such as IO, DB or webservice call) the thread can be used for something else, such as executing another we request. 这意味着当您的应用程序正在等待其他内容(例如IO,DB或Webservice调用)时,线程可以用于其他内容,例如执行我们请求的其他内容。 This doesn't mean that an DB-call will be executed faster. 这并不意味着将更快地执行数据库调用。 But it will let the thread do something else while waiting. 但是它会让线程在等待时做其他事情。 If you're using IIS the number of threads are limited. 如果您使用的是IIS,则线程数是有限的。 So instead of locking them with expensive IO, they can serve another request while waiting. 因此,与其在昂贵的IO上锁定它们,不如在等待时为另一个请求提供服务。

  2. You may do more things at the same time. 您可以同时做更多的事情。 For example, you could send a request to you DB, while executing a slow webservice call at the same time. 例如,您可以向数据库发送请求,同时执行缓慢的Web服务调用。 This may cause the total execution time to be faster, since you're doing more things at the same time. 这可能会导致总执行时间更快,因为您要同时执行更多操作。 However, there are limitations. 但是,有局限性。 For instance, if you're using Entity Framework, only one thread may access the context at the time. 例如,如果您使用的是Entity Framework,则此时只有一个线程可以访问上下文。 But while waiting for the DB, you can do something else. 但是,在等待数据库时,您可以执行其他操作。 For example: 例如:

    public class MyThreadingClass { 公共类MyThreadingClass {
    private Task ExecuteWebServiceCallAsync() { return await _myService.DoSomething(); 私有任务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; } 

    } }

So, to sum up. 因此,总结一下。 The reason why you should use await/async is when you can do it ALL THE WAY down to the execution of the slow operation (such as DB or webservice). 之所以应使用await / async,是因为您可以一直执行直到慢速操作(例如DB或Webservice)的执行。 Or if you wish to do several things at once. 或者,如果您想一次做几件事。

In your particular case you can do something like this: 在您的特定情况下,您可以执行以下操作:

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,
     };
}

But try to avoid Task.Run since it's considered an anti-pattern. 但是请尽量避免Task.Run,​​因为它被认为是反模式。 Instead, try to use await/async all the way from the controller to the actual operation (DB, IO, webservice). 而是尝试从控制器到实际操作(DB,IO,Web服务)的整个过程中使用await / async。 Also, in the example above there's a lot of threading going on. 另外,在上面的示例中,有很多线程在进行。 It should likely be cleaned up a bit, but you can see it as a proof-of-concept more than the suggested solution. 可能应该对其进行一些清理,但您可以将其视为概念证明,而不是建议的解决方案。

You can actually have an async controller so you don't need to call .Result which renders async operation to run synchronously. 实际上,您可以有一个异步控制器,因此您无需调用.Result即可使异步操作同步运行。

something like: 就像是:

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