async/await
を久しぶりに書いていたら少し忘れてしまっていたので学び直しです。・・・
1. Task.Run(async () => await ...).Wait();
の問題点
C# でバックグラウンドスレッドを利用する際、以下のように Task.Run
を Wait()
で待機することがあります。
Task.Run(async () => await DoSomethingAsync()).Wait();
しかし、これは以下の問題を引き起こします。
❌ Wait()
の問題点
- メインスレッドがブロックされる → 非同期のメリットが失われる
- UIスレッド(WPF/WinForms)でフリーズの原因になる
- デッドロックが発生する可能性がある
- 例外が
AggregateException
にラップされるため扱いにくい
✅ 解決策
await Task.Run(async () => await DoSomethingAsync());
これにより、メインスレッドをブロックせずに非同期処理を実行できます。
2. バックグラウンドで処理を並行実行する方法
方法1: Task.Run
で非同期実行
Task.Run(async () => await DoBackgroundWorkAsync());
✅ ポイント
-
await
しないので メインスレッドをブロックしない -
Task.Run
の戻り値を無視することで 完全に独立した処理 になる
方法2: Task
を保存してあとで await
Task backgroundTask = Task.Run(async () => await DoBackgroundWorkAsync());
// 他の処理を並行して実行
Console.WriteLine("メインスレッドで別処理");
// あとで結果を待つ
await backgroundTask;
✅ ポイント
-
Task
を保存することで、好きなタイミングでawait
できる
方法3: Fire and Forget(例外処理付き)
Task.Run(async () =>
{
try
{
await DoBackgroundWorkAsync();
}
catch (Exception ex)
{
Console.WriteLine($"エラー発生: {ex.Message}");
}
});
✅ ポイント
-
await
しないので メインスレッドはブロックされない -
try-catch
で 例外処理を適切に行う
3. .Wait()
と .Result
の違い
メソッド | 動作 | 例外の扱い | デッドロックの危険性 |
---|---|---|---|
.Wait() |
タスクが完了するまで 同期的に待つ |
AggregateException にラップ |
あり |
.Result |
タスクが完了するまで 同期的に待ち、結果を取得 |
AggregateException にラップ |
あり |
❌ デッドロックの危険性
特に UIスレッド で Result
や Wait()
を使うと、デッドロックが発生しやすくなります。
string result = Task.Run(async () => await GetDataAsync()).Result; // デッドロックの危険
✅ 解決策 → async/await
を使う
private async void button_Click(object sender, EventArgs e)
{
string result = await GetDataAsync();
MessageBox.Show(result);
}
4. まとめ
❌ 避けるべきコード
Task.Run(async () => await DoSomethingAsync()).Wait();
理由:
- メインスレッドをブロックする
- デッドロックの可能性
- 例外が
AggregateException
にラップされる
✅ 推奨される実装
バックグラウンドで非同期処理を開始
Task.Run(async () => await DoBackgroundWorkAsync());
Task
を保存してあとで await
Task backgroundTask = Task.Run(async () => await DoBackgroundWorkAsync());
// 他の処理を実行
await backgroundTask;
UIアプリでデッドロックを避ける
private async void button_Click(object sender, EventArgs e)
{
string result = await GetDataAsync();
MessageBox.Show(result);
}
結論:
Wait()
や Result
を避け、可能な限り async/await
を使うのが最適!