[解決済み] デッドロックを引き起こす非同期/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()
?
なぜ上記の例でデッドロックが発生するのか、誰か説明してください。 何が問題なのか全く分かりません.
どのように解決するのですか?
を見てみましょう。 この例 をご覧ください。Stephenが明確な答えを持っています。
<ブロッククオート
つまりこれは、トップレベルのメソッドから始まって、(
Button1_Click
UI の場合
MyController.Get
ASP.NETの場合)。
-
トップレベルのメソッドが呼び出す
GetJsonAsync
(を呼び出します(UI/ASP.NETのコンテキスト内)。 -
GetJsonAsync
を呼び出すことで、REST リクエストを開始します。HttpClient.GetStringAsync
を呼び出すことでRESTリクエストを開始します (まだコンテキスト内)。 -
GetStringAsync
は、未完成のTask
を返します。これは REST リクエストが完了していないことを示します。 -
GetJsonAsync
を待ちます。Task
が返すGetStringAsync
. コンテキストはキャプチャされ、引き続きGetJsonAsync
メソッドを後で実行し続けるために使われます。GetJsonAsync
は未完成のTask
であることを示すGetJsonAsync
メソッドが完全ではないことを示します。 -
トップレベルのメソッドが同期的にブロックされ
Task
が返すGetJsonAsync
. これはコンテキストスレッドをブロックします。 -
... 最終的に、RESTリクエストが完了します。これで
Task
によって返されたGetStringAsync
. -
の続きは
GetJsonAsync
は実行可能な状態になり、コンテキストが利用可能になるのを待ち、 コンテキストで実行できるようになります。 -
デッドロック . トップレベルのメソッドはコンテクストスレッドをブロックし
GetJsonAsync
が完了するのを待ち、そしてGetJsonAsync
はコンテキストが解放され、完了するのを待っています。UI の例では、"context" は UI コンテキスト、ASP.NET の例では "context" は ASP.NET リクエスト コンテキストです。このタイプのデッドロックは、どちらの"context" でも発生する可能性があります。
もうひとつ、読んでおきたいリンクがあります。 待ち時間、UI、そしてデッドロック! なんと!
関連
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】"指定されたパスのフォーマットはサポートされていません。"
-
[解決済み] await vs Task.Wait - デッドロック?
-
[解決済み] forEachループでasync/awaitを使用する
-
[解決済み] async」と「await」の使い方とタイミング
-
[解決済み] 非同期Task<T>メソッドを同期的に実行するにはどうしたらいいですか?
-
[解決済み] 非同期関数+await+setTimeoutの組合せ
-
[解決済み] 複数のタスクにasync/awaitを使用する
-
[解決済み] C#でawaitを使わずに非同期メソッドを安全に呼び出す方法
-
[解決済み】非同期プログラミングとマルチスレッドの違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C#で四捨五入する方法
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】Sequence contains no matching element(シーケンスにマッチする要素がない
-
[解決済み】バックスラッシュを含むパス文字列のエスケープシーケンスが認識されない件
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み】Nullableオブジェクトは値を持たなければならない?