异步\等待方法

异步\等待方法

问题描述:

我是一个新的异步/等待功能,我试图在我的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() 此方法创建了一个过程并从数据库中获取信息(该方法没有任何问题地执行),但是当我尝试返回堆栈时(正如我在死亡日志中那样)时。

我会很开心,如果有人知道这是为什么发生。

+0

你可以提供适当格式的方法吗? –

+0

@ÖmerCinbat - 我已经提交了一个编辑,目前正在等待同行评审。 – smoksnes

+1

您对await + Task.Run的使用是毫无意义且实际有害的。我建议你研究*为什么和何时*异步是好的。 – usr

使用异步/ AWAIT模式时,您不需要使用Task.Run。

+0

我尝试没有Task.Run(),但我没有它收到的时间是一样的,因为我不使用await(所以逻辑是这样的不是异步) –

+1

@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个主要优点:

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

  2. 您可以在同一时间做更多的事情。例如,您可以向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。另外,在上面的例子中,有很多线程正在进行。它可能会被清理一些,但你可以将它看作是一个概念验证,而不是建议的解决方案。

+0

谢谢,我现在就试试吧! –

+0

我试过了你的建议,但我收到的时间与我不使用异步/等待时相同。 –

+0

一件事:我想在 公共执行方法异步任务 GetIndexViewModel(IEnumerable的参数,布尔isMore =假,布尔currentRole = FALSE) 异步并且使时间的情况下 –

实际上你可以有一个异步控制器,所以你不需要调用.Result,它使异步操作同步运行。

类似:

public Task<ActionResult> Index(object parameter) 
{ 
    var model = await this.quantService.GetIndexViewModel(companyIds, isMore, currentRole); 

    return View(model); 
} 
+0

我以这种方式尝试,它的工作,但我收到的时间是,当我没有异步/等待执行方法相同。 感谢您的建议。 –

我解释你在我的博客上看到了僵局。总之,don't block on async code;而是使用async all the way

但您的方法还存在其他问题。正如其他人所指出的,await Task.Run是ASP.NET上的反模式。你可能想阅读我的文章async ASP.NET

最后,还有一个提示:你正从错误的方向接近问题。您应该首先考虑您的应用程序正在做什么,而不是仅选择一种方法来“制作异步”,而是开始将I/O调用转换为最低级别的异步。将它们转换为使用异步API而不是阻塞API(即没有0​​)。然后将其调用者更改为异步,并将他们的调用者更改为异步,最终将您的控制器方法更改为异步。