導入
非同期には2種類の「待ち」があります。ネットワークやファイルの待ち時間(IOバウンド)はawaitで待つだけ。一方、重い計算などのCPUバウンドな作業はUIを止めないようTask.Runで別スレッドへ逃がします。あわせて、時間のかかる処理を途中で「やめて」と伝えるCancellationTokenを学びます。
図解
flowchart TB
IO["IOバウンド(通信・ファイル)"] -->|待つだけ| AW["await で待機"]
CPU["CPUバウンド(重い計算)"] -->|別スレッドへ| TR["Task.Run で実行"]
CT["CancellationToken"] -->|Cancel| STOP["処理を途中で中断"]
サンプル
// Task.Run: 重い計算(CPUバウンド)を別タスクへ逃がし、結果を await で受け取る
int result = await Task.Run(() =>
{
int sum = 0;
for (int i = 1; i <= 100; i++) sum += i;
return sum;
});
Console.WriteLine(result); // 5050
// CancellationToken: 「やめて」を伝える仕組み
using var cts = new CancellationTokenSource();
cts.Cancel(); // ここでは即キャンセルして挙動を見る
try
{
await Task.Delay(1000, cts.Token); // キャンセル済みなので待たずに例外
Console.WriteLine("完了");
}
catch (TaskCanceledException)
{
Console.WriteLine("キャンセルされました"); // こちらが出力される
}
- IOバウンド(通信・ファイル)の待ちは
awaitだけでよい。Task.Runで包む必要はない - CPUバウンド(重い計算)は
Task.Runで別スレッドへ逃がし、awaitで結果を受け取る CancellationTokenSourceのTokenを渡し、Cancel()で処理の中断を要求できる- キャンセルされた
Task.Delay等はTaskCanceledException(OperationCanceledException)を投げる
演習
// TODO: Task.Run の中で 1〜10 の合計を計算し、await で受け取って出力してください(55)
int total = ___;
Console.WriteLine(total);
- 期待される出力:
55
ヒント1を見る
await Task.Run(() => { int s = 0; for (int i = 1; i <= 10; i++) s += i; return s; })
ヒント2を見る
上の式をtotalに代入します
まとめ
- 待ち時間(IOバウンド)は
await、重い計算(CPUバウンド)はTask.Run CancellationTokenで長い処理に中断要求を伝えられる- キャンセル時は
TaskCanceledExceptionが飛ぶ
次回: 非同期処理での例外の扱いです。