私は完全に非同期の API クライアントを使用しています。つまり、各操作は または を返しますTask
。Task<T>
例:
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
C# 5 の async/await 演算子を使用して、複数のタスクを開始し、それらがすべて完了するまで待機する正しい/最も効率的な方法は何ですか。
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
または:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
API クライアントは内部的に HttpClient を使用しているため、5 つの HTTP リクエストが直ちに発行され、各リクエストが完了するとコンソールに書き込まれることが予想されます。
ベストアンサー1
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
上記のコードでは操作を並行して実行しますが、このコードは各操作が実行される各スレッドをブロックします。たとえば、ネットワーク呼び出しに 2 秒かかる場合、各スレッドは待機以外の何もせずに 2 秒間ハングします。
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
一方、上記のコードはWaitAll
現在のスレッドもブロックし、操作が終了するまでスレッドは他の作業を自由に処理できなくなります。
推奨されるアプローチ
WhenAll
操作を非同期で並列に実行するものを優先します。
public async Task DoWork() {
int[] ids = new[] { 1, 2, 3, 4, 5 };
await Task.WhenAll(ids.Select(i => DoSomething(1, i, blogClient)));
}
実際、上記のケースでは、
await
継続がないので、 をする必要すらなく、メソッドから直接戻ることができます。
public Task DoWork() { int[] ids = new[] { 1, 2, 3, 4, 5 }; return Task.WhenAll(ids.Select(i => DoSomething(1, i, blogClient))); }
これを裏付けるために、すべての代替案とその利点/欠点を詳しく説明したブログ投稿を以下に示します。ASP.NET Web API で同時非同期 I/O を実行する方法と場所