本文へスキップ
BecomeCoder

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

Task.Run と CancellationToken

ブラウザで完結

導入

非同期には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で結果を受け取る
  • CancellationTokenSourceTokenを渡し、Cancel()で処理の中断を要求できる
  • キャンセルされたTask.Delay等はTaskCanceledExceptionOperationCanceledException)を投げる

演習

// 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が飛ぶ

次回: 非同期処理での例外の扱いです。

実際に動かしてみよう

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

C# — ブラウザ内で実行

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