C# では Task
を使った非同期処理と、Parallel
クラスを使った並列処理を実装できます。一見似ている両者ですが、目的や動作の仕組みは異なります。違いを理解して適切に使い分けることで、効率的で無駄のないプログラムを構築できます。本記事では「非同期処理」と「並列処理」の違いを整理し、Task
と Parallel
の使い分けを解説します。
非同期処理(Task)の特徴
非同期処理とは「処理の完了を待たずに次の処理へ進む」仕組みです。主に I/O 待機(ファイル読み書き、ネットワーク通信、DBアクセス)に効果を発揮します。CPU は待機中に別の仕事を進められるため、アプリ全体の応答性が向上します。
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
Console.WriteLine("処理開始");
// 非同期処理(I/O 待ち)
var task = ReadDataAsync();
Console.WriteLine("別の処理を実行中...");
var data = await task;
Console.WriteLine($"結果: {data}");
}
static async Task<string> ReadDataAsync()
{
await Task.Delay(2000); // 疑似的なI/O待ち
return "データ取得完了";
}
}
この例ではデータ取得を待っている間に別の処理を進めることができ、UIアプリならフリーズを防げます。
並列処理(Parallel)の特徴
並列処理とは「複数の処理を同時に走らせる」仕組みです。主に CPU 計算が重い処理を分割して並列化することで、高速化を狙います。Parallel.For
や Parallel.ForEach
を利用します。
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Console.WriteLine("並列処理開始");
Parallel.For(0, 5, i =>
{
Console.WriteLine($"{i} の計算開始");
Task.Delay(1000).Wait(); // 疑似的な重い処理
Console.WriteLine($"{i} の計算終了");
});
Console.WriteLine("すべて完了");
}
}
ループの各要素がスレッドプール上で同時に実行され、全体の処理時間を短縮できます。
非同期処理と並列処理の違い
項目 | 非同期処理(Task/async-await) | 並列処理(Parallel) |
---|---|---|
目的 | I/O 待ちを効率化し応答性を高める | CPU 計算を分割して高速化する |
動作 | 待機中はスレッドを解放して他処理を進める | 複数スレッドで処理を同時実行する |
得意分野 | ネットワーク通信、ファイルI/O、DBアクセス | 数値計算、画像処理、シミュレーション |
制御方法 | async/await 、Task |
Parallel.For 、Parallel.ForEach |
TaskとParallelの使い分け
- I/O 待ち処理: 非同期処理(
Task
+async/await
)を選ぶ - CPU 集中処理: 並列処理(
Parallel
)を選ぶ - 両方を組み合わせることも可能(例:大量のファイルを並列に読み込みつつ、各読み込みを非同期で処理)
まとめ
非同期処理と並列処理は似て非なるものです。
- 非同期処理(Task)は I/O 待ちを効率化し、応答性を向上させる
- 並列処理(Parallel)は CPU 計算を分割し、処理を高速化する
- 用途に応じて正しく使い分けることが重要
適切に活用すれば、C# アプリケーションのパフォーマンスとユーザー体験を大きく改善できます。