简体   繁体   English

何时使用“await”关键字

[英]When to use the “await” keyword

I'm writing a web page, and it calls some web services. 我正在写一个网页,它会调用一些Web服务。 The calls looked like this: 这些电话看起来像这样:

var Data1 = await WebService1.Call();
var Data2 = await WebService2.Call();
var Data3 = await WebService3.Call();

During code review, somebody said that I should change it to: 在代码审查期间,有人说我应该将其更改为:

var Task1 = WebService1.Call();
var Task2 = WebService2.Call();
var Task3 = WebService3.Call();

var Data1 = await Task1;
var Data2 = await Task2;
var Data3 = await Task3;

Why? 为什么? What's the difference? 有什么不同?

Servy's answer is correct; Servy的回答是正确的; to expand on that a little. 稍微扩大一点。 What's the difference between: 有什么区别:

Eat(await cook.MakeSaladAsync());
Eat(await cook.MakeSoupAsync());
Eat(await cook.MakeSandwichAsync());

and

Task<Salad> t1 = cook.MakeSaladAsync();
Task<Soup> t2 = cook.MakeSoupAsync();
Task<Sandwich> t3 = cook.MakeSandwichAsync();
Eat(await t1);
Eat(await t2);
Eat(await t3);

?

The first is: 首先是:

  • Cook, please make me a salad 库克,请给我一份沙拉
  • While waiting for the salad, you have some free time to brush the cat. 在等沙拉时,你有空闲时间刷猫。 When you're done that, oh, look, the salad is done. 当你做完了,哦,看,沙拉完成了。 If the cook finished the salad while you were brushing the cat, they did not start on making the soup because you haven't asked for it yet . 如果厨师在你刷猫的时候吃完沙拉,他们就没有开始制作汤,因为你还没有要求它
  • Eat the salad. 吃沙拉。 The cook is now idle while you eat. 你吃饭的时候,厨师现在闲着。
  • Cook, please make me some soup. 库克,请给我一些汤。
  • While waiting for the soup you have some free time to clean the fish tank. 在等待汤的同时,你有一些空闲时间来清理鱼缸。 When you're done that, oh, look, the soup is done. 当你完成它,哦,看,汤完成了。 If the cook finishes the soup while you are cleaning the fish tank, they do not start on the sandwich because you haven't asked for it yet. 如果厨师在你清洗鱼缸时完成了汤,他们就不会开始吃三明治,因为你还没有要求它。
  • Eat the soup. 吃汤。 The cook is now idle while you eat. 你吃饭的时候,厨师现在闲着。
  • Cook, please make me a sandwich. 库克,请给我一个三明治。
  • Again, find something else to do while you're waiting. 再次,在等待时找到别的事情。
  • Eat the sandwich. 吃三明治。

Your second program is equivalent to: 你的第二个计划相当于:

  • Cook, please make me a salad 库克,请给我一份沙拉
  • Cook, please make me some soup. 库克,请给我一些汤。
  • Cook, please make me a sandwich. 库克,请给我一个三明治。
  • Is the salad done? 沙拉做完了吗? If not, while waiting for the salad, you have some free time to brush the cat. 如果没有,在等沙拉时,你有空闲时间刷猫。 If the cook finished the salad while you were brushing the cat, they started making the soup . 如果厨师在你刷猫的时候吃完沙拉,他们就开始做汤了
  • Eat the salad. 吃沙拉。 The cook can still be working on the soup and sandwich while you are eating. 在你吃饭的时候,厨师仍然可以做汤和三明治。
  • Is the soup done? 汤做完了吗? ... ...

You see the difference? 你看到了区别? In your original program you don't tell the cook to start the next course until you are done eating the first course. 在原来的计划,你不告诉厨师,开始下一疗程,直到你吃完第一道菜。 In your second program you request all three courses up front, and eat them -- in order -- as they come available. 在你的第二个课程中,你提前申请所有三个课程,并按顺序吃它们 - 因为它们可用。 The second program makes better use of the cook's time because the cook can "get ahead" of you. 第二个程序更好地利用了厨师的时间,因为厨师可以“领先”你。

In the first code snippet you're not even starting the second service call until the first service call completes (and likewise not starting the third until the second completes). 在第一个代码片段中,您甚至不会在第一个服务调用完成之前启动第二个服务调用(同样在第二个服务调用完成之前不会启动第三个服务调用)。 In short, they are executed sequentially. 简而言之,它们是按顺序执行的。

In the second snippet you start all three service calls, but then don't continue on in the code until all three are done. 在第二个片段中,您启动所有三个服务调用,但在代码完成之前不要继续执行。 In short, they are all executed in parallel. 简而言之,它们都是并行执行的。

If the second/third calls are unable to be started until they have the result of the previous operation then you would need to do something like the first snippet in order to make it work. 如果第二次/第三次调用无法启动,直到它们具有上一次操作的结果,那么您需要执行类似第一个代码段的操作才能使其正常工作。 If the service calls don't depend on each other at all then you'd want them to be executed in parallel for performance reasons. 如果服务调用完全不依赖于彼此,那么出于性能原因,您希望它们并行执行。

If, for some reason, you really dislike having the extra local variables, there are other ways of executing the tasks in parallel using alternate syntaxes. 如果由于某种原因,您真的不喜欢使用额外的局部变量,那么还有其他方法可以使用备用语法并行执行任务。 One alternative that would act like your second option is: 一种可能与您的第二种选择相似的替代方案是:

var Data = await Task.WhenAll(WebService1.Call(), 
    WebService2.Call(), 
    WebService3.Call());

Servy posted a very good answer, but here is a visual description using Task s to help show what the problem is. Servy发布了一个非常好的答案,但这是一个使用Task来帮助显示问题的视觉描述。 This code will not be functionaly the same as yours (it does not do all the synchronization context stuff like giving back control to the message pump) but it illustrates the problem very well. 这段代码与你的代码不同(它没有完成所有同步上下文的操作,例如将控制权交还给消息泵),但它很好地说明了这个问题。

Your code is doing something like this 你的代码正在做这样的事情

var fooTask = Task.Factory.StartNew(Foo);
fooTask.Wait();
var fooResult = fooTask.Result;

var barTask = Task.Factory.StartNew(Bar);
barTask.Wait();
var barResult = barTask.Result;

var bazTask = Task.Factory.StartNew(Baz);
bazTask.Wait();
var bazResult = bazTask.Result;

and the corrected code is doing something like this 并且纠正的代码正在做这样的事情

var fooTask = Task.Factory.StartNew(Foo);
var barTask = Task.Factory.StartNew(Bar);
var bazTask = Task.Factory.StartNew(Baz);

fooTask.Wait();
var fooResult = fooTask.Result;
barTask.Wait();
var barResult = barTask.Result;
bazTask.Wait();
var bazResult = bazTask.Result;

You can see that all 3 tasks are running while waiting for the first result to get back, where in the first example the 2nd task does not start until the first task is finished. 您可以看到所有3个任务在等待第一个结果返回时正在运行,在第一个示例中,第二个任务在第一个任务完成之前不会启动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM