web-dev-qa-db-ja.com

C#でawait asyncがどのように機能するか

私はC#でawait asyncがどのように機能するかを理解しようとしていますが、1つのことは私をたくさん混乱させています。 awaitキーワードを使用するすべてのメソッドは、asyncでマークする必要があることを理解しています。私の理解では、awaitキーワードを含む行がヒットすると、その行の下のコードは実行されません。 await行のステートメントを実行するために非同期操作が開始され、制御が呼び出しメソッドに返され、実行を続行できます。

質問#1:この仮定は正しいですか、それともawaitキーワードの下のコードはまだ実行されていますか?

次に、非同期のサービスメソッドを呼び出し、その結果を返す必要があるとします。 returnステートメントはawaitキーワードの下にあります。

質問2:非同期呼び出しが完了した後、またはその前に、returnステートメントがヒットするのはいつですか?

質問3:そのサービス呼び出しの結果を使用したいのですが、非同期操作は結果が返されたときに呼び出し元のメソッドをヒットさせるのに役立ちません。これは、呼び出しを同期するResultプロパティを使用して実行できることを理解しています。しかし、DBオペレーションで非同期を使用すると、ほとんどのアプリで実際に80%の時間がかかるようになります。

質問4:DB操作で非同期を使用するにはどうすればよいですか?可能ですか?

質問#5:どのscenraioが非同期操作が役立つかは、すべてのapiが理由なく非同期操作を行っているようですまたは非同期操作を使用するポイントを逃しましたか?

APIが理由なしにasynメソッドを作成していると言うことは、メソッドが何かを返す必要があるためであり、その計算がどのように戻ることができるまで、本質的には呼び出しがブロックされることはありません結果が返されますか?

53
Afraz Ali

MSDN すべてを説明

ただし、Vanillaのドキュメント(特にMSDNから)を特定の状況に適用するのが難しい場合があることを理解しているので、ポイントを見ていきましょう。

質問#1:この仮定は正しいですか、それともawaitキーワードの下のコードはまだ実行されていますか?

「await」キーワードの下のコードは、非同期呼び出しが完了したときにのみ実行されます。それまでの間、メソッドは「非同期」とマークされているため、メソッドが完了するまで、メソッドの呼び出し元に制御が返されます。上記のMSDNリンクから:

Task<string> getStringTask = client.GetStringAsync("http://msdn.Microsoft.com");

// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();

// The await operator suspends AccessTheWebAsync. 
//  - AccessTheWebAsync can't continue until getStringTask is complete. 
//  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
//  - Control resumes here when getStringTask is complete.  
//  - The await operator then retrieves the string result from getStringTask. 
string urlContents = await getStringTask;

コメントは非常に説明的だと思います。

次に、非同期のサービスメソッドを呼び出し、その結果を返す必要があるとします。 returnステートメントはawaitキーワードの下にあります。

質問2:非同期呼び出しが完了した後、またはその前に、returnステートメントがヒットするのはいつですか?

後。

質問3:そのサービス呼び出しの結果を使用したいのですが、非同期操作は結果が返されたときに呼び出し元のメソッドをヒットさせるのに役立ちません。これは、呼び出しを同期するResultプロパティを使用して実行できることを理解しています。しかし、DBオペレーションで非同期を使用すると、ほとんどのアプリで実際に80%の時間がかかるようになります。

サービスを完了するために3つの無関係なDBクエリを作成し、結果に基づいて計算を実行し、終了する必要があるとします。これを連続して行った場合、各操作が完了するまで待つ必要があります。非同期呼び出しを使用すると、C#は3つのクエリを並行して実行し、サービスがより早く終了する可能性があります。

また、Taskを返す操作はFutureとして使用できます。 MSDN on Futures を参照してください。ここでは、futureに基づいて作業を並列化し、結果をマージする方法に関するいくつかのパターンについて説明しています。

サービスに必要なDB呼び出しが1つだけの場合、非同期で呼び出すのは間違いなく悪化します。

質問4:DB操作で非同期を使用するにはどうすればよいですか?可能ですか?

ADO.NETには、非同期メソッド ReadAsyncおよびNextResultAsync が含まれるようになりました。

推奨されているように、この議論は here と書くよりもはるかに完全です。

質問#5:どのscenraioが非同期操作が役立つかは、すべてのapiが理由なく非同期操作を行っているようですまたは非同期操作を使用するポイントを逃しましたか?

非同期操作は、スレッドの問題に陥ることなく、長時間実行されている操作を簡単に並列化するのに非常に便利です。メソッドが1つのことだけを行う場合、または一連の単純な(高速の)ことを行う場合は、非同期にするのは無意味です。ただし、複数の長時間実行される操作がある場合、スレッドを管理するよりも非同期で並列化する方がはるかに簡単でエラーが少なくなります。

56

あなたの質問のほとんどは、私が書いた officialdocumentationintro post で回答されています。

質問4:DB操作で非同期を使用するにはどうすればよいですか?出来ますか

Entity Framework 6(現在ベータ版)はasyncをサポートしています。下位レベルのデータベースAPIは、何らかの方法で非同期操作をサポートします。それらのいくつか(SQLiteなど)はasyncを直接サポートします。他の人は、単純なasync互換のラッパーを書く必要があります。

...そして推奨?

はい、バックエンドの非スケーラブルな単一データベースマシンと通信するフロントエンドサーバー(ASP.NETなど)を作成している場合を除きます。その特定のケースでは、フロントエンドをスケーリングしても意味がありません。バックエンドは、いずれにしてもそれに合わせてスケーリングできないからです。

質問#5:どのscenraioが非同期操作が役立つかは、すべてのapiが理由なく非同期操作を行っているようですまたは非同期操作を使用するポイントを逃しましたか?

非同期操作の利点は次のとおりです。

  1. クライアント(UI)側では、アプリケーションの応答性が維持されます。
  2. サーバー側では、アプリケーションのスケーラビリティが向上します。
14
Stephen Cleary