本文へスキップ
BecomeCoder

C#実践コース · 第1章 非同期プログラミング · レッスン3

並行実行(WhenAll)

ブラウザで完結

導入

3件の通信を1件ずつ待つと3倍の時間がかかります。同時に始めてまとめて待つと、全体の待ち時間が大幅に短縮されます。それがTask.WhenAllです。

図解

flowchart TB
    subgraph 順番に待つ["逐次: 遅い"]
        S1["A待つ"] --> S2["B待つ"] --> S3["C待つ"]
    end
    subgraph 同時["WhenAll: 速い"]
        P1["A"]
        P2["B"]
        P3["C"]
    end
    同時 --> DONE["全部終わるのを1回で待つ"]

サンプル

// 3つの Task を「先に始めて」おく(この時点で並行に走り出す)
Task<int> a = FetchAsync(1);
Task<int> b = FetchAsync(2);
Task<int> c = FetchAsync(3);

// WhenAll で全部の完了をまとめて待つ
int[] results = await Task.WhenAll(a, b, c);
Console.WriteLine($"合計: {results.Sum()}");   // 合計: 60

async Task<int> FetchAsync(int id)
{
    await Task.Delay(50);   // それぞれ50ms。逐次なら150ms、並行なら約50ms
    return id * 10;
}
  • 先に複数のTaskを開始しておくと、それらは並行に進む
  • Task.WhenAll(...)で全部の完了をまとめて待つ
  • 逐次実行より全体の待ち時間が大幅に短縮される

演習

Task<int> t1 = GetAsync(100);
Task<int> t2 = GetAsync(200);

// TODO: t1 と t2 を WhenAll でまとめて待ち、合計を "300" と出力してください
async Task<int> GetAsync(int v) { await Task.Delay(10); return v; }
___
  • 期待される出力: 300
ヒント1を見る

int[] r = await Task.WhenAll(t1, t2);

ヒント2を見る

Console.WriteLine(r.Sum());

まとめ

  • 複数Taskを先に開始すると並行に進む
  • Task.WhenAllで全完了をまとめて待つ
  • 逐次より待ち時間を大幅短縮できる

次回: 重い計算を逃がすTask.Runと、処理を中断するCancellationTokenです。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。