4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C# でのバックグラウンド処理と `async/await` の正しい使い方を学ぶ

Posted at

async/awaitを久しぶりに書いていたら少し忘れてしまっていたので学び直しです。・・・

1. Task.Run(async () => await ...).Wait(); の問題点

C# でバックグラウンドスレッドを利用する際、以下のように Task.RunWait() で待機することがあります。

Task.Run(async () => await DoSomethingAsync()).Wait();

しかし、これは以下の問題を引き起こします。

Wait() の問題点

  1. メインスレッドがブロックされる → 非同期のメリットが失われる
  2. UIスレッド(WPF/WinForms)でフリーズの原因になる
  3. デッドロックが発生する可能性がある
  4. 例外が 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スレッドResultWait() を使うと、デッドロックが発生しやすくなります。

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 を使うのが最適!

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?