C#5での非同期操作の紹介

前回 Jeffrey Richter AsyncEnumeratorクラスReactive Extensionsライブラリを使用して、 非同期操作の操作を簡単にする方法について説明しました。 ただし、 Halesbergと会社が最近言ったように、新しいC#言語バージョンのリリースにより幸福がもたらされ、非同期操作で作業するときにサードパーティを使用する必要がなくなり、自転車を使用する必要がなくなります。



C#5の非同期操作の根底にある考え方は、ジェフリー・リヒターがAsyncEnumeratorクラスで使用した考え方と非常に似ていますが、今回はコンパイラーがあなたと古いリヒターについても発見しました(これは好みに大きな影響を与えます)この構文糖)。 まず、前に使用した独創的な例の同期バージョンに戻りましょう。





static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  1. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  2. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  3. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  4. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  5. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  6. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  7. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  8. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  9. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  10. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  11. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  12. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  13. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  14. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  15. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  16. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  17. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  18. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



  19. static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .



static void SyncVersion() { Stopwatch sw = Stopwatch.StartNew(); string url1 = "http://rsdn.ru" ; string url2 = "http://gotdotnet.ru" ; string url3 = "http://blogs.msdn.com" ; var webRequest1 = WebRequest.Create(url1); var webResponse1 = webRequest1.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url1, webResponse1.ContentLength, sw.ElapsedMilliseconds); var webRequest2 = WebRequest.Create(url2); var webResponse2 = webRequest2.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url2, webResponse2.ContentLength, sw.ElapsedMilliseconds); var webRequest3 = WebRequest.Create(url3); var webResponse3 = webRequest3.GetResponse(); Console .WriteLine( "{0} : {1}, elapsed {2}ms" , url3, webResponse3.ContentLength, sw.ElapsedMilliseconds); } * This source code was highlighted with Source Code Highlighter .







ここではすべてが非常にシンプルです(そして最も重要なのは非常に独創的です!):私たちはブラウザのようなものを書いているふりをするか、または何もすることがなく、3つのWebページのコンテンツを取得する必要があります。 同期バージョンは、この操作を非同期で実行することで可能な限り3倍待機することを除いて、常に動作します。 すでに悪いことに気付いてHalesbergのスピーチを楽しんでいるので、彼と同じように、2回のマウスストロークとキーボードの3回のクリックでここで試して、この素晴らしい同期メソッドを非同期にしています。



最初に行うことは、関数の宣言を次のように変更することです。







  1. static async void AsyncVersion()
*このソースコードは、 ソースコードハイライターで強調表示されました。




メソッドシグネチャのasyncキーワード (CTPバージョンではキーワード、リリースではcontextキーワード)は、このメソッドが非同期で実行され、非同期操作の開始直後に呼び出し元のコードに制御を返すことを示します。 非同期メソッドは、 voidTask、およびTask <T>の3つの戻りタイプのいずれかを返すことができます。 メソッドがvoidを返す場合、この操作の結果を処理することは不可能であるため(このメソッド内で例外を処理しない場合はうまくクラッシュし、適切にクラッシュする可能性があります)、「started and forgot」(「fire and forget」)タイプの非同期操作になりますプロセス全体を引き寄せます!)。 いくつかのシナリオでは、これは便利な場合があります(たとえば、すべてのリモートサブスクライバーに非同期的に通知する必要があり、これらのメッセージを受信するかどうかは気にしません)。 好奇心reader盛な読者であるTaskクラスとTask <T>クラス(レドモンドの愛する会社が私たち全員が新機能をリリースするペースにまだ完全に飽きていません)は、。バージョン。 これらのクラスの主なアイデアは、「不完全なタスク」をカプセル化し、それが完了するまで待機し、「継続」(このタスクが完了したときに呼び出す必要のあるもの)などを確立できることです。 Task <T>クラスはTaskクラスの継承であり、 Resultプロパティを使用してT型の戻り値を取得できる点でTaskクラスと異なります。一方、 Taskクラスは、一部のタスクがvoidを返す可能性が高く、その副作用。



非同期操作を実行するだけでなく、その実行結果も取得したいので、結果は私たちにとって重要ではなく、副作用であるため...一般に、戻り値としてTaskタイプを使用します(安全にTask < string>ですが、一般に、これはそれほど重要ではありません)。



メソッドのシグネチャを変更したら、少しとその本体を変更する必要があります。 この形式の行の場合:







  1. var webResponse1 = webRequest1.GetResponse();
*このソースコードは、 ソースコードハイライターで強調表示されました。




次のものに置き換える必要があります。







  1. var webResponse1 = await webRequest1.GetResponseAsync();
*このソースコードは、 ソースコードハイライターで強調表示されました。




awaitキーワード (リリースではこれはコンテキストキーワードにもなります)は、要求された非同期操作が完了するまでコードのこの時点に固執することを意味しません。 これは混乱を招く可能性があります(また、 エリックと会社は他のキーワードを探すことを提案します)が、それはまったく反対の考えを意味します。 awaitキーワードは、非同期操作の開始後(この場合、 WebResponseを受信する非同期操作の開始後)、メソッドが制御を返し、非同期操作の完了後に同じ場所から続行することを意味します。 賢明な言葉で言えば、これは続編と呼ばれ、エリックはそれについて彼の頭を冷やすことができるたくさんの記事を持っています。



matanに入らない場合、この場合、C#のイテレーターブロックで並列を描画できます(このトピックに慣れていない場合は、 修正することを強くお勧めします)。どちらの場合でも、コンパイラーは、メソッドの実行は中断され、後続の呼び出しで実行を正しく復元するために使用されます。 ただし、イテレータの場合、外部コードによるMoveNextメソッドの後続の呼び出しでイテレータブロックの実行が再開する場合、非同期操作の完了後、非同期メソッドは自動的に実行され続けます。 これを行うには、現在のタスクの「継続」として、現在のタスクが終了したときに呼び出される現在のメソッドが設定されます。



修正されたメソッド全体がここにあります:







  1. 静的非同期タスクAsyncVersion()
  2. {
  3. ストップウォッチsw = Stopwatch.StartNew();
  4. string url1 = "http://rsdn.ru1" ;
  5. 文字列 url2 = "http://gotdotnet.ru" ;
  6. string url3 = "http://blogs.msdn.com" ;
  7. var webRequest1 = WebRequest.Create(url1);
  8. Console .WriteLine( "webRequest1.GetResponseAsync()の前。スレッドID:{0}"
  9. Thread.CurrentThread.ManagedThreadId);
  10. var webResponse1 = await webRequest1.GetResponseAsync();
  11. Console .WriteLine( "{0}:{1}、経過{2}ミリ秒。スレッドID:{3}" 、url1
  12. webResponse1.ContentLength、sw.ElapsedMilliseconds、
  13. Thread.CurrentThread.ManagedThreadId);
  14. var webRequest2 = WebRequest.Create(url2);
  15. Console .WriteLine( "webRequest2.GetResponseAsync()の前。スレッドID:{0}"
  16. Thread.CurrentThread.ManagedThreadId);
  17. var webResponse2 = await webRequest2.GetResponseAsync();
  18. Console .WriteLine( "{0}:{1}、経過{2}ミリ秒。スレッドID:{3}" 、url2
  19. webResponse2.ContentLength、sw.ElapsedMilliseconds、
  20. Thread.CurrentThread.ManagedThreadId);
  21. var webRequest3 = WebRequest.Create(url3);
  22. Console .WriteLine( "webRequest3.GetResponseAsync()の前。スレッドID:{0}"
  23. Thread.CurrentThread.ManagedThreadId);
  24. var webResponse3 = webRequest3.GetResponseAsync();
  25. Console .WriteLine( "{0}:{1}、経過{2}ミリ秒。スレッドID:{3}" 、url3、
  26. webResponse3.ContentLength、sw.ElapsedMilliseconds、
  27. Thread.CurrentThread.ManagedThreadId);
  28. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




(正直に言うと、メソッドを現在実行しているスレッドで表示されるように出力をコンソールに変更しましたが、これは明確にするためです。したがって、この変更はカウントされません。しかし、いずれにしても、古いHalesberg 、実際には、最小量)。



そして、これがこのメソッドの呼び出し方法です。







  1. static void Main( string [] args)
  2. {
  3. 試してみる
  4. {
  5. Console .WriteLine( "メインスレッドID:{0}" 、Thread.CurrentThread.ManagedThreadId);
  6. var task = AsyncVersion();
  7. Console .WriteLine( "AsyncVersion()メソッド呼び出しの直後" );
  8. //非同期操作の完了を待っています
  9. task.Wait();
  10. Console .WriteLine( "非同期タスクが完了しました!" );
  11. }
  12. catch (System.AggregateException e)
  13. {
  14. // TPLのすべての例外は、AggregateExceptionにラップされてスローされます
  15. Console .WriteLine( "AggregateException:{0}" 、e.InnerException.Message);
  16. }
  17. Console .ReadLine();
  18. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




そして、その実行結果は次のとおりです。



メインスレッドID:10



webRequest1.GetResponseAsync()の前。 スレッドID:10





AsyncVersion()メソッド呼び出しの直後





rsdn.ru:1672 、経過657ms。 スレッドID:13



webRequest2.GetResponseAsync()の前。 スレッドID:13





gotdotnet.ru:99470、1915ms 経過しました。 スレッドID:14



webRequest3.GetResponseAsync()の前。 スレッドID:14





blogs.msdn.com:47927 、経過2628ms。 スレッドID:15



非同期タスクが終了しました!





そして、この獣の中で何が起こっているのか見てみましょう。 したがって、 AsyncVersionメソッドは現在のスレッドで呼び出され、最初のawaitステートメントの直後に制御が戻ります。 ただし、制御を呼び出し元のコードに戻す前に、 AsyncVersionメソッド現在のタスクの「継続」として設定され、実行を継続する場所が記憶されます。 この関数はTaskタイプのオブジェクトを返すので、完了を待って結果を確認できます。 次に、非同期操作の完了後、実行は前の場所から再開され、見てのとおり、既に別のスレッドにあります。 さらに、このプロセスは3番目の非同期操作が完了するまで続き、その後task.Waitメソッドが制御を返し、コンソールに「非同期タスクが完了しました!」と表示されます。



エラー処理にもいくつかの変更が加えられましたが、非常に小さな変更も加えられています。 既にTPLに精通している場合は、すべての例外を「収集」して内部に蓄積する、使い慣れたSystem.AggregateExcpetionクラスを認識するでしょう。 その理由は、1つのタスクに多数の子タスクを含めることができ、各子タスクにはさらにいくつかの「サブタスク」を含めることができ、この「ツリー」タスクの各タスクは独自の例外で落ちる可能性があるためです。 AggregateExceptionは、この問題の解決策として機能します。Flattenメソッドを使用して簡単に「直線化」できる例外の「ツリー」が含まれています(詳細については、「AggregateExceptionの操作」などセクションを参照)。 一般に、エラー処理がそれほど複雑にならず、これをAPMで作業するときに対処しなければならない悪夢と比較すると、そのような「複雑さ」は、指を呼び出しても問題になりません。



実際、この例は同期とそれほど変わりません。 結局、3つの非同期操作を連続して実行し、後続の各操作は前の操作が完了した後にのみ開始されます。 2番目の例では、3つのWebページから結果を同時に受信し、その結果をファイルに非同期で書き込む新しい形式で書き直してみましょう。







  1. public static async void AsyncVersion2()
  2. {
  3. ストップウォッチsw = Stopwatch.StartNew();
  4. var urls = new string [] { "http://rsdn.ru""http://gotdotnet.ru"
  5. "http://blogs.msdn.com" };
  6. var tasks =(URLのURL から
  7. let webRequest = WebRequest.Create(url)
  8. 新しい {Url = url、Response = webRequest.GetResponseAsync()}を選択します
  9. .ToList();
  10. var data = await TaskEx.WhenAll(tasks.Select(t => t.Response));
  11. var sb = new StringBuilder ();
  12. foreach (タスクのvar
  13. {
  14. sb.AppendFormat( "{0}:{1}、経過{2}ミリ秒。スレッドID:{3}" 、s.Url、
  15. s.Response.Result.ContentLength、
  16. sw.ElapsedMilliseconds、Thread.CurrentThread.ManagedThreadId)
  17. .AppendLine();
  18. }
  19. var outputText = sb.ToString();
  20. Console .WriteLine( "Webリクエストの結果:{0}" 、outputText);
  21. var fs = new FileStream"d:\\ results.txt "FileMode .Create、
  22. FileAccess.Write、 FileShare .Write))
  23. {
  24. 待つ
  25. fs.WriteAsync(UnicodeEncoding.Default.GetBytes(outputText)、0、
  26. UnicodeEncoding.Default.GetByteCount(outputText));
  27. }
  28. }
*このソースコードは、 ソースコードハイライターで強調表示されました。


これはすでに面白いです! 完全に非同期のコードを取得しましたが、インディアンの群れが数晩にわたってそれに取り組んだようには見えません(同様の複雑さの非同期コードはまさにそのように見えます)。 それは理解可能であり、同様に同期して読み取ります! (誰も信じていない場合は、古典的なAPMスタイルでこのコードを書き直してみてください)。



では、何がありますか? 自分の足を撃つことを恐れずに使用するのに本当に便利なものがあります。 さらに、深刻なジャングルに入らなくても、このビジネスの使い方は多かれ少なかれ明確です(名前に慣れる必要がありますが)。 そして最も興味深いのは、これがすべての機能とは程遠いことです。 同期コンテキストや、このビジネスをユーザーインターフェイススレッドでどのようにうまく使用できるか、TAP(タスクベースの非同期パターン)とは何であるかについては話しませんでしたが、使用したすべての新しい非同期メソッドが拡張メソッドを使用し、好きなだけ追加することができます。実装のジャングルには入りませんでした...しかし、それはすべてです。 そして今日は、このものをダウンロードして自分で試してみることをお勧めします!



(私はほとんど忘れていました、長い間探していないように、ここにURLがあります:msdn.com/vstudio/async)



All Articles