Async await关键字是否等同于ContinueWith lambda?


81

有人可以请我确认我是否正确理解Async await关键字吗?(使用CTP版本3)

到目前为止,我已经知道,在方法调用之前插入await关键字实际上可以完成两件事:A。它创建立即返回,B。它创建一个“ continuation”,在异步方法调用完成时调用。无论如何,延续是该方法的代码块的其余部分。

所以我想知道的是,这两个代码在技术上是否等效,如果是,这是否基本上意味着await关键字与创建ContinueWith Lambda相同(即,它基本上是一个编译器的快捷方式)?如果没有,有什么区别?

bool Success =
    await new POP3Connector(
        "mail.server.com", txtUsername.Text, txtPassword.Text).Connect();
// At this point the method will return and following code will
// only be invoked when the operation is complete(?)
MessageBox.Show(Success ? "Logged In" : "Wrong password");

VS

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text ).Connect())
.ContinueWith((success) =>
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password"));

Answers:


83

总体思路是正确的-该方法的其余部分被制成各种形式的延续。

“快速通道”的博客文章有如何的细节async/await编译器改造工程。

差异,浮现在脑海:

await关键字还使用“调度环境”的概念。调度上下文是(SynchronizationContext.Current如果存在)回退TaskScheduler.Current。然后,继续在调度上下文上运行。因此,如果需要的话,可以更近似地传递TaskScheduler.FromCurrentSynchronizationContextContinueWith,然后再回落TaskScheduler.Current

实际async/await实现基于模式匹配;它使用“等待”模式,该模式允许等待任务以外的其他事情。WinRT异步API,一些特殊的方法(例如YieldRx observables)和特殊的套接字等待(socket awaitables)等例子对GC的影响并不大。任务功能强大,但并不是唯一可以等待的任务。

还有一个细微的挑剔的区别:如果等待已完成,则该async方法实际上不会在该点返回;它同步地继续。因此,这有点像传递TaskContinuationOptions.ExecuteSynchronously,但是没有与堆栈相关的问题。


2
说得很好-我试着顺应乔恩的帖子,因为它们的内容比我有时间在SO上回答的内容要广泛得多,但史蒂芬绝对是正确的。WRT值得期待的(尤其是GetAwaiter),他的帖子3非常有帮助,恕我直言:) msmvps.com/blogs/jon_skeet/archive/2011/05/13/…–
James Manning

4
斯蒂芬在这里。对于简单的示例,很容易认为async / await只是ContinueWith的快捷方式-但是,我想反过来考虑。异步/等待实际上是您以前用于ContinueWith的更强大的表达。问题是ContinueWith(...)使用lambda,并允许执行转移到延续,但是如果必须将循环主体的一半放在ContinueWith(。 。)和另一半。您最终将获得手动继续链接。
Theo Yaung 2012年

7
异步/等待比ContinueWith(...)更具表现力的另一个示例是异常流动。您可以在同一个try块中等待多次,对于执行的每个阶段,可以将它们的异常集中到同一catch(...)块中,而不必编写大量的代码来明确执行此操作。
Theo Yaung 2012年

2
值得注意的是async / await的最后一部分是“更高级别的概念”,而ContinueWith(...)是更手动的,并且显式具有lambda,委托创建等。有了更高级别的概念,就有更多的优化机会-因此例如,在同一方法中多次等待实际上“共享”了同一lambda闭包(就像单个lambda的开销一样),而ContinueWith(...)每次调用都会得到开销,因为您显式编写了一个lambda,因此编译器将其提供给您。
Theo Yaung 2012年

1
@MobyDisk:澄清一下,await仍然SynchronizationContext.Current像往常一样捕获。但是在ASP.NET Core上SynchronizationContext.Currentnull
史蒂芬·克雷里

8

“本质上”是这样,但是生成的代码的作用远不止于此。有关生成的代码的更多详细信息,我强烈推荐Jon Skeet的Eduasync系列:

http://codeblog.jonskeet.uk/category/eduasync/

特别是,第7条介绍了生成的内容(从CTP 2开始)以及原因,因此,很可能适合您目前正在寻找的内容:

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generation-code-from-a-simple-async-method/

编辑:我认为它可能比您从问题中寻找的内容更详细,但是如果您想知道方法中有多个等待时的情况,请参见第9篇文章:)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generation-code-for-multiple-awaits/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.