web-dev-qa-db-ja.com

待機中の複数の並列非同期呼び出し

私の知る限り、ランタイムが以下のステートメントに出くわすと、非同期で呼び出されるメソッド(この例ではsomeCall())へのコールバックとして関数の残りの部分をラップします。この場合、anotherCall()someCall()へのコールバックとして実行されます。

_    await someCall();
    await anotherCall();
_

ランタイムを次のように実行できるかどうか疑問に思います。非同期でsomeCall()を呼び出し、すぐに呼び出し元のスレッドに戻ってから、同様にanotherCall()を呼び出します(someCallが完了するのを待たずに)。非同期で実行するにはこれらの2つのメソッドが必要であり、これらの呼び出しは単に起動して呼び出しを忘れると仮定するためです。

asyncawaitだけを使用してこのシナリオを実装することは可能ですか(古いbegin/endメカニズムを使用していません)?

37
rovsen

Async/awaitには、WhenAllWhenAnyなど、並列合成を支援するいくつかの演算子が含まれています。

var taskA = someCall(); // Note: no await
var taskB = anotherCall(); // Note: no await

// Wait for both tasks to complete.
await Task.WhenAll(taskA, taskB);

// Retrieve the results.
var resultA = taskA.Result;
var resultB = taskB.Result;
51
Stephen Cleary

最も簡単な方法は、おそらくこれを行うことです。

var taskA = someCall();
var taskB = someOtherCall();
await taskA;
await taskB;

結果の値が必要な場合、これは特に便利です。

var result = await taskA + await taskB;

したがって、taskA.Resultを実行する必要はありません。

TaskEx.WhenAllは、2つが互いに待機するよりも速い場合があります。パフォーマンスの調査を行っていないのでわかりませんが、問題が発生しない限り、特に結果の値がわからない場合は、2つの連続した待機の方が読みやすいと思います。

6
Cellfish

.NET 4.5を使用している場合、非同期CTPは不要になりました。非同期機能はコンパイラーによって実装されるため、.NET 4アプリで使用できますが、コンパイルするにはVS2012が必要です。

TaskExはもう必要ありません。 CTPは既存のフレームワークを変更できなかったため、拡張機能を使用して、言語が5.0で処理することを実現しました。タスクを直接使用するだけです。

そこで、これにより、TaskExをTaskに置き換えることで、コードを書き直しました(Stephen Clearyが回答)。

var taskA = someCall(); // Note: no await
var taskB = anotherCall(); // Note: no await

// Wait for both tasks to complete.
await Task.WhenAll(taskA, taskB);

// Retrieve the results.
var resultA = taskA.Result;
var resultB = taskB.Result;
2
myaseedk