【问题标题】:Is Async await keyword equivalent to a ContinueWith lambda?Async await 关键字是否等同于 ContinueWith lambda?
【发布时间】:2012-02-04 17:40:20
【问题描述】:

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

到目前为止,我已经发现在方法调用之前插入 await 关键字基本上做了两件事,A. 它创建一个立即返回和 B. 它创建一个在异步方法完成时调用的“延续”调用。无论如何,延续是该方法的代码块的其余部分。

所以我想知道的是,这两段代码在技术上是否等效,如果是,这是否基本上意味着 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"));

【问题讨论】:

    标签: c# async-await continuations


    【解决方案1】:

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

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

    特别是,第 7 篇文章介绍了生成的内容(截至 CTP 2)以及原因,因此可能非常适合您目前正在寻找的内容:

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

    编辑:我认为它可能比您从问题中寻找的内容更详细,但是如果您想知道当您在方法中有多个等待时会是什么样子,请参阅帖子 #9: )

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

    【讨论】:

      【解决方案2】:

      一般的想法是正确的——方法的其余部分被变成了排序的延续。

      "fast path" blog post 详细介绍了 async/await 编译器转换的工作原理。

      差异,在我脑海中浮现:

      await 关键字也使用了“调度上下文”概念。调度上下文为SynchronizationContext.Current(如果存在),则返回TaskScheduler.Current。然后继续在调度上下文上运行。因此,更接近的方法是将TaskScheduler.FromCurrentSynchronizationContext 传递给ContinueWith,如有必要,再使用TaskScheduler.Current

      实际的async/await实现是基于模式匹配的;它使用“等待”模式,允许等待任务以外的其他事情。一些示例是 WinRT 异步 API、一些特殊方法,例如 Yield、Rx observables 和 special socket awaitables that don't hit the GC as hard。任务很强大,但它们并不是唯一的等待对象。

      我想到了一个更细微的细微差别:如果 awaitable 已经完成,那么 async 方法此时实际上并没有返回;它同步继续。所以这有点像传递TaskContinuationOptions.ExecuteSynchronously,但没有堆栈相关的问题。

      【讨论】:

      • 说得很好 - 我尽量推迟 Jon 的帖子,因为它们比我有时间回答 SO 的任何内容都要广泛得多,但 Stephen 绝对正确。 WRT 什么是可等待的(尤其是 GetAwaiter),他的帖子 #3 非常有帮助,恕我直言 :) msmvps.com/blogs/jon_skeet/archive/2011/05/13/…
      • 斯蒂芬的位置在这里。对于简单的示例,很容易认为 async/await 只是 ContinueWith 的快捷方式 - 但是,我喜欢反过来考虑它。 Async/await 实际上是您过去使用 ContinueWith 的更强大的表达方式。问题是 ContinueWith(...) 使用 lambdas,并允许将执行转移到继续,但是如果您必须将一半循环体放在 ContinueWith(.. .) 和另一半之后。您最终会得到手动延续链接。
      • 另一个 async/await 比 ContinueWith(...) 更具表现力的例子是异常流动。您可以在同一个 try 块中 await 多次,并且对于每个执行阶段,它们的异常可以集中到同一个 catch(...) 块中,而无需编写大量代码来显式执行此操作。
      • async/await 的最后一个值得注意的部分是它是一个“更高级别的概念”,而 ContinueWith(...) 更加手动并且明确地具有 lambdas、委托创建等。具有更高级别的概念有更多的优化机会 - 例如,同一方法中的多个等待实际上“共享”相同的 lambda 闭包(这就像单个 lambda 的开销),而 ContinueWith(...) 每次调用它时都会获得开销, 因为你明确地写了一个 lambda,所以编译器把它给了你。
      • @MobyDisk:澄清一下,await 仍然像往常一样捕获SynchronizationContext.Current。但在 ASP.NET Core 上,SynchronizationContext.Currentnull
      猜你喜欢
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      • 2017-10-14
      • 2014-12-05
      • 2021-12-11
      • 1970-01-01
      • 2023-03-27
      • 2013-06-04
      相关资源
      最近更新 更多