.NET 非同期タスクでのデッドロックの回避: Task.Result
トラップ
.NET 非同期操作内で Task
の Result
プロパティにアクセスすると、予期せずデッドロックが発生する可能性があります。 この問題を説明する一般的なシナリオを見てみましょう。
問題:
ExecuteAsync
メソッド (非同期操作) が UI スレッドから開始される多層アプリケーションを想像してください。このメソッドはデータベースと対話し、Task
を返します。 その後、UI スレッドが asyncTask.Result
を使用してタスクの結果を取得しようとすると、アプリケーションがフリーズします。
根本原因:
この問題は、ランタイムが await
ステートメントの後の実行フローを管理する方法に起因します。 デフォルトでは、非同期操作の継続は、SynchronizationContext
が発生したのと同じ await
でスケジュールされます。
この例では、ExecuteAsync
は UI スレッドから呼び出されます。 したがって、その継続 (await
の後のコード) も UI スレッドでスケジュールされます。 ただし、asyncTask.Result
がアクセスされると (UI スレッドがブロックされると)、継続は実行されません。これによりデッドロックが発生します。継続は UI スレッドを待機し、UI スレッドは継続が完了するのを待機します。
解決戦略:
一貫した非同期/待機: 最も簡単な解決策は、コード全体で一貫して async
/await
を使用することです。これにより、継続が適切にスケジュールされ、デッドロックが回避されます。
async
修飾子の削除: async
/await
の使用が不可能な場合は、関連するメソッドから async
修飾子を削除します。 これにより、メソッドが同期メソッドに変換され、デッドロック状態が解消されます。
ConfigureAwait(false)
: 元の ConfigureAwait(false)
での継続のスケジュールを明示的に回避するには、SynchronizationContext
を使用します。これには、Result
がアクセスされるすべてのメソッドにこの呼び出しを追加する必要があり、複雑さが増します。
重要なポイント:
Task.Result
を使用する場合にデッドロックが発生する可能性を理解することは、堅牢な非同期コードを作成するために重要です。提案されたソリューションを採用することで、開発者はデッドロックを効果的に防止し、スムーズで応答性の高いアプリケーションを確保できます。
以上が.NET で Task.Result にアクセスするとデッドロックが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。