本文へスキップ
BecomeCoder

C#実践コース · 第11章 モダンC#実務 · レッスン62

Parallel と PLINQ ― 並列処理

ローカル実施

導入

async/await は「待ち時間を無駄にしない(I/Oバウンド向き)」しくみでした。一方、**「重い計算を複数のCPUコアで同時にこなす(CPUバウンド向き)」**には ParallelPLINQ を使います。ブラウザ内ランナーは単一スレッドのため、ここではコード例で読みます。

説明

flowchart TB
    W["大量の重い計算"] --> P["Parallel.ForEach / AsParallel"]
    P --> C1["コア1"]
    P --> C2["コア2"]
    P --> C3["コア3"]
    style P fill:#fff3e0

サンプル

// Parallel.ForEach: 各要素の処理を複数コアに割り振る
var files = new[] { "a.txt", "b.txt", "c.txt" };
Parallel.ForEach(files, file =>
{
    // 重い処理(画像変換・集計など)を各コアで並行に
    Console.WriteLine($"処理中: {file}");
});

// PLINQ: LINQ に .AsParallel() を付けるだけで並列化
int[] numbers = Enumerable.Range(1, 1_000_000).ToArray();
long total = numbers.AsParallel().Where(n => n % 2 == 0).Sum(n => (long)n);
Console.WriteLine(total);
  • Parallel.For / Parallel.ForEach繰り返しを複数コアに分散する
  • PLINQAsParallel())は LINQ クエリを並列実行する
  • 向いているのはCPUバウンド(重い計算)。I/O待ちには async/await を使う
  • 並列では共有状態の書き換えが危険(スレッド安全に注意。lock/Interlocked/Concurrentコレクション)
  • 数が少なかったり1件が軽すぎると、分散の管理コストで逆に遅くなることもある

演習

手元で Enumerable.Range(1, 20_000_000) を、.Sum().AsParallel().Sum() の両方で Stopwatch を使って時間を比べてみましょう。並列化が効く規模感を体で覚えられます。

まとめ

  • Parallel / PLINQ は重い計算を複数コアで同時にこなす(CPUバウンド向き)
  • I/O待ちは async/await、重い計算は並列、と使い分ける
  • 共有状態の書き換えはスレッド安全に注意する

次回: JSONを実務レベルで制御する System.Text.Json です。