デッドロックを引き起こす async/await の例 質問する

デッドロックを引き起こす async/await の例 質問する

私は、C# async/awaitキーワードを使用した非同期プログラミングのベスト プラクティスをいくつか見つけました (私は C# 5.0 を初めて使用します)。

与えられたアドバイスの 1 つは次のとおりでした。

安定性: 同期コンテキストを把握する

... 一部の同期コンテキストは再入不可でシングル スレッドです。つまり、特定の時点でコンテキスト内で実行できる作業単位は 1 つだけです。この例としては、Windows UI スレッドや ASP.NET 要求コンテキストがあります。これらのシングル スレッド同期コンテキストでは、デッドロックに陥りやすくなります。シングル スレッド コンテキストからタスクを生成し、コンテキスト内でそのタスクを待機すると、待機中のコードがバックグラウンド タスクをブロックする可能性があります。

public ActionResult ActionAsync()
{
    // DEADLOCK: this blocks on the async task
    var data = GetDataAsync().Result;

    return View(data);
}

private async Task<string> GetDataAsync()
{
    // a very simple async method
    var result = await MyWebService.GetDataAsync();
    return result.ToString();
}

自分で分析してみると、メイン スレッドは で新しいスレッドを生成しますMyWebService.GetDataAsync();が、メイン スレッドはそこで待機しているため、 の結果を待機しますGetDataAsync().Result。その間に、データが準備できたとします。メイン スレッドが継続ロジックを続行せず、 から文字列の結果を返さないのはなぜでしょうかGetDataAsync()

上記の例でデッドロックが発生する理由を誰か説明してもらえますか? 何が問題なのか全くわかりません...

ベストアンサー1

を見てみましょうこの例スティーブンはあなたに明確な答えを持っています:

したがって、トップレベルのメソッド ( Button1_ClickUI の場合 / MyController.GetASP.NET の場合) から始めると、次のようになります。

  1. トップレベルのメソッド呼び出しGetJsonAsync(UI/ASP.NET コンテキスト内)。

  2. GetJsonAsyncHttpClient.GetStringAsync呼び出して(コンテキスト内で) REST リクエストを開始します。

  3. GetStringAsyncTaskREST リクエストが完了していないことを示すuncompleted を返します。

  4. GetJsonAsyncTaskによって返される を待機しますGetStringAsync。コンテキストはキャプチャされ、GetJsonAsync後でメソッドの実行を続行するために使用されます。は、メソッドが完了していないことを示す、GetJsonAsync未完了の を返します。TaskGetJsonAsync

  5. トップレベルのメソッドは、Taskによって返されたを同期的にブロックしますGetJsonAsync。これにより、コンテキスト スレッドがブロックされます。

  6. ... 最終的に、REST リクエストが完了します。これTaskにより、 によって返された が完了しますGetStringAsync

  7. 継続の実行GetJsonAsync準備が整い、コンテキストが使用可能になるまで待機して、コンテキスト内で実行できるようになります。

  8. デッドロック最上位のメソッドはコンテキスト スレッドをブロックし、GetJsonAsync完了を待機し、GetJsonAsync完了できるようにコンテキストが解放されるのを待機しています。UI の例では、「コンテキスト」は UI コンテキストです。ASP.NET の例では、「コンテキスト」は ASP.NET 要求コンテキストです。このタイプのデッドロックは、どちらの「コンテキスト」でも発生する可能性があります。

もう一つ読んでおくべきリンク:Await、UI、そしてデッドロック! ああ、大変!

おすすめ記事