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

有没有人能好心地确认一下我是否正确理解了异步等待关键字?(使用 CTP 的第3版)

到目前为止,我已经计算出在方法调用之前插入 wait 关键字实际上做了两件事,A。它创造了一个立即的回报和 B。它创建一个“延续”,在异步方法调用完成时调用。在任何情况下,延续都是该方法的代码块的剩余部分。

所以我想知道的是,这两段代码在技术上是否是等价的,如果是的话,这是否意味着 wait 关键字与创建 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"));
21563 次浏览

It's "essentially" that, but the generated code does strictly more than just that. For lots more detail on the code generated, I'd highly recommend Jon Skeet's Eduasync series:

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

In particular, post #7 gets into what gets generated (as of CTP 2) and why, so probably a great fit for what you're looking for at the moment:

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

EDIT: I think it's likely to be more detail than what you're looking for from the question, but if you're wondering what things look like when you have multiple awaits in the method, that's covered in post #9 :)

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

The general idea is correct - the remainder of the method is made into a continuation of sorts.

The "fast path" blog post has details on how the async/await compiler transformation works.

Differences, off the top of my head:

The await keyword also makes use of a "scheduling context" concept. The scheduling context is SynchronizationContext.Current if it exists, falling back on TaskScheduler.Current. The continuation is then run on the scheduling context. So a closer approximation would be to pass TaskScheduler.FromCurrentSynchronizationContext into ContinueWith, falling back on TaskScheduler.Current if necessary.

The actual async/await implementation is based on pattern matching; it uses an "awaitable" pattern that allows other things besides tasks to be awaited. Some examples are the WinRT asynchronous APIs, some special methods such as Yield, Rx observables, and special socket awaitables that don't hit the GC as hard. Tasks are powerful, but they're not the only awaitables.

One more minor nitpicky difference comes to mind: if the awaitable is already completed, then the async method does not actually return at that point; it continues synchronously. So it's kind of like passing TaskContinuationOptions.ExecuteSynchronously, but without the stack-related problems.