導入
非同期には有名な落とし穴があります。awaitすべきところで.Resultや.Wait()を使うと、処理が永久に止まるデッドロックを招くことがあります。正しい作法を身につけましょう。
図解
flowchart TB
G["非同期処理"] -->|await で待つ| OK["正しい:固まらず完了 ✅"]
G -->|Result や Wait でブロック| NG["危険:状況次第で永久停止 🛑"]
style OK fill:#e8f5e9
style NG fill:#ffebee
サンプル
// ✅ 正しい: 非同期は最後まで await でつなぐ
int value = await GetValueAsync();
Console.WriteLine(value); // 42
// ❌ 危険(このエンジンでも実際に停止/エラーになるため実行しない):
// int bad = GetValueAsync().Result; // .Result はブロッキング → デッドロックの温床
// GetValueAsync().Wait(); // .Wait() も同様
async Task<int> GetValueAsync()
{
await Task.Delay(30);
return 42;
}
awaitすべき箇所で.Result/.Wait()を使うとブロッキングになり、デッドロックの原因になる- 原則:非同期は呼び出しの一番上まで
async/awaitでつなぐ(“async all the way”) async voidは例外を捕捉できず危険。イベントハンドラ以外ではasync Taskを使う
演習
// TODO: GetNameAsync を「正しい作法」で await し、"名前: Taro" と出力してください
// (.Result や .Wait() は使わない)
async Task<string> GetNameAsync() { await Task.Delay(10); return "Taro"; }
___
- 期待される出力:
名前: Taro
ヒント1を見る
string name = await GetNameAsync();
ヒント2を見る
Console.WriteLine($"名前: {await GetNameAsync()}");
まとめ
.Result/.Wait()のブロッキングはデッドロックの温床- 非同期は一番上まで
async/awaitでつなぐ async voidは避け、async Taskを使う
次回: 複数の処理が同じデータを触るときの「スレッド安全」です。