2016-03-07 69 views
1

我一直在研究如何将异步方法并入我的MVC控制器,特别是利用并行执行的潜力。寻找澄清Task.WhenAll并等待在异步MVC的网络应用程序

我发现this article特别有帮助。不过,我希望澄清一个概念。我上面链接文章使用下面的代码并行执行一系列I/O密集型方法:

var widgetTask = widgetService.GetWidgetsAsync(); 
var prodTask = prodService.GetProductsAsync(); 
var gizmoTask = gizmoService.GetGizmosAsync(); 

await Task.WhenAll(widgetTask, prodTask, gizmoTask); 

var pwgVM = new ProdGizWidgetVM(
    widgetTask.Result, 
    prodTask.Result, 
    gizmoTask.Result 
    ); 

我想知道的是如何从下面的代码不同:

var widgetTask = widgetService.GetWidgetsAsync(); 
var prodTask = prodService.GetProductsAsync(); 
var gizmoTask = gizmoService.GetGizmosAsync(); 

var pwgVM = new ProdGizWidgetVM(
    await widgetTask, 
    await prodTask, 
    await gizmoTask 
    ); 

根据我的理解,这两个代码块是等效的。那是对的吗?如果不是这样,如果有人能够解释这种差异并提出哪种方案更适合我,那将会很棒。

+3

第一个片段等待所有*任务完成。第二,顺序等待它们,并不是最简单的代码来维护。想象一下,例如试图在所有任务完成后添加断点,以检查其结果。在#1中琐碎,在#2中不可能。 –

+0

对,我明白你的意思。这是我没有考虑过的一个重要问题。但为了完整理解,我是否正确地说在#2中方法仍然是并行执行的?在那种情况下,顺序地等待结果并不重要,因为无论如何,只有一切都完成,我才能继续。 – getsetcode

+1

'await'不影响执行。当您调用异步方法时,任务开始执行。 await只影响异步*等待*。从这个意义上讲,这两个片段是相同的。但它可能仍然很重要,因为编译器必须生成一个3步状态机来等待而不是1步状态机。编译器可能足够聪明,可以*优化*第二个片段,并用'await Task.WhenAll'代替它,但我怀疑它 –

回答

0

1将执行所有3个任务并行,但不一定为了

Task.WhenAll完成,当所有任务中已完成。 widgetTask将被执行到第一个等待状态,然后在等待异步执行io界限的工作时,prodTask将被执行到第一个等待状态,同时仍然等待前两个任务完成,gizmoTask将被执行到第一个等待状态。然后在所有3个完成并行执行io-bound工作后,它们将运行完成。在此之后,Task.WhenAll也将报告完成。

2将在平行和在给定的顺序

widgetTask将开始执行所有3个任务,然后将prodTask开始,然后gizmoTask。你开始等待widgetTask。完成后,它将返回并且此任务内部的非io绑定代码将运行。完成后,将等待prodTask。由于它的io绑定工作发生异步,它可能已经完成,所以这将是相当快的。 io-bound工作完成后,在prodTask内部等待之后进行编码将被调用。同样的gizmoTask

所以通常你想要的版本1,而不是版本2,只要你不关心任务执行后的等待代码的顺序。

+2

所有三个任务在调用时开始。在“Task.WaitAll”中全部等待3或单独不会改变这一点。现在如果在'GetWidgetsAsync'调用之前的'awaits',那么你会是正确的,但事实并非如此。 – juharr

+0

谢谢。正如我怀疑的那样,通过了解异步和等待是不完整的。这完全解释了。 – getsetcode

+1

@getsetcode这个答案是错误的。您应该听取Panagiotis在他的评论中提出的意见。 – juharr