2012-01-07 19 views
74

Async awaitキーワードが正しく理解されているかどうかを確認するのに十分親切にしてもらえますか? (CTPのバージョン3を使用して)Async awaitキーワードはContinueWith lambdaと同等ですか?

これまでのところ、メソッド呼び出しの前にawaitキーワードを挿入すると、基本的に2つのことが行われました。A.即時の戻り値とBを作成します。非同期メソッド呼び出しの完了時に呼び出されます。いずれにしても、継続はメソッドのコードブロックの残りの部分です。

私はこの2つのビットが技術的に同等であると思いますが、これは基本的に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")); 

答えて

73

一般的な考えが正しい - メソッドの残りの部分は、種類の継続中に行われます。

"fast path" blog postには、コンパイラ変換の仕組みについての詳細が記載されています。私の頭の上から

違い、:

awaitキーワードも「スケジューリングコンテキスト」という概念を利用します。スケジューリングコンテキストはSynchronizationContext.Current(存在する場合)、TaskScheduler.Currentに戻っています。次に、継続はスケジューリングコンテキストで実行されます。したがって、より近い近似は、をContinueWithに渡し、必要に応じてTaskScheduler.Currentに戻ることになります。

実際のasync/await実装はパターンマッチングに基づいています。それは、タスク以外の他のものが待つことを可能にする「待つことができる」パターンを使用する。いくつかの例は、WinRT非同期API、Yield、Rx observables、およびspecial socket awaitables that don't hit the GC as hardなどの特殊なメソッドです。タスクは強力ですが、唯一の待望のものではありません。

もう少し微妙な相違点があります。待ち時間がすでに完了している場合、asyncメソッドは実際にその時点では返されません。同期的に継続します。だから、TaskContinuationOptions.ExecuteSynchronouslyを渡すようなものですが、スタック関連の問題はありません。

+2

非常にうまくいっています - 私は、SOの回答に入れる時間があるものよりもはるかに広範であるため、ジョンの投稿に延期しようとしますが、スティーブンは絶対に正しいです。 WRTは何が待ち受けているか(特にGetAwaiter)、彼の投稿#3は非常に役に立ちますIMHO :) http://msmvps.com/blogs/jon_skeet/archive/2011/05/13/eduasync-part-3-the-shape- async-method-awaitable-boundary.aspx –

+4

ここにスティーブンのスポットがあります。シンプルな例では、async/awaitがContinueWithのショートカットに過ぎないと考えるのは簡単ですが、逆の考え方が好きです。 Async/awaitは、実際にはContinueWithを使用するためのもののより強力な表現です。問題は、ContinueWith(...)がlambdasを使用しており、実行を継続に移すことができますが、ContinueWith(...の前にループ本体の半分を配置する必要がある場合はループなどの他の制御フローの概念は不可能です。 。)と残りの半分。手動連鎖連鎖で終わる。 –

+7

async/awaitがContinueWith(...)よりはるかに表現的である別の例では、例外が流れています。同じtryブロック内で複数回待つことができます。実行の各段階で、例外を明示的に行うコードを書くことなく、例外を同じcatch(...)ブロックに集めることができます。 –

8

それはちょうどそれより厳密に多くないことが、生成されたコード "本質的" です。生成されたコードの多くの詳細については、私は非常にジョンスキートの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/

関連する問題