481

私は完全に非同期の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リクエストがすぐに発行され、それぞれが完了するたびにコンソールに書き込まれると思います。

4

7 に答える 7

669
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はスレッドもブロックし、スレッドは操作が終了するまで他の作業を自由に処理できません。

推奨されるアプローチ

WhenAllParallelで非同期に操作を実行する方が望ましいです。

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 の方法と場所

于 2012-09-09T11:35:03.193 に答える
26

呼び出している API は非同期であるため、Parallel.ForEachバージョンはあまり意味がありません。並列性が失われるため、このバージョンでは使用.WaitしないでくださいWaitAll。呼び出し元が非同期の場合の別の代替手段は、実行Task.WhenAll後に使用しSelectToArrayタスクの配列を生成することです。2 番目の代替手段は、Rx 2.0 を使用することです。

于 2012-09-09T11:51:07.360 に答える