web-dev-qa-db-ja.com

非非同期/待機コードでのAsyncLocal <T>の効果は何ですか?

私はデスクトップwinformアプリケーションの非常に大きくて古いコードベースに取り組んでいます。このコードベースでは、主にBackgroundWorkerを使用して、バックグラウンドスレッドで実行される多くの操作があります。

このコードベースの一般的なパターンは、実行中のスレッドにアーティファクトをバインドすることで複雑さを隠すことです。たとえば、データベース接続とトランザクションは[ThreadStatic]フィールドに保存されます。

これを変更して、async/awaitコードの使用を開始し、プールの任意のスレッドでタスクを実行し、ConfigureAwait(false)を使用してタスクを他のスレッドで実行し続けることができるようにします。 。 [ThreadStatic]async/awaitとうまく機能しないことは知っています。代わりに、AsyncLocal<T>を使用することを提案するいくつかの回答をここで読みました。

前述のように、大規模なコードベースで作業しているため、1回のショットでどこでもasync/awaitに切り替えることができず、この変更を徐々に行う必要があります。したがって、以前は[ThreadStatic]があったコードはAsyncLocal<T>に変更されますが、コードの大部分は引き続きBackgroundWorkerを使用し、コードの1行のasync/awaitにヒットしません。 。

質問
これは機能しますか?新しいasync/awaitコードで機能するある種のコンテキストフローを定義できる必要があります。また、[ThreadStatic]に依存していた古い非同期コードでも機能し続け、すべてのスレッドをそれぞれから独立させます。その他。

私が完全に間違っていて、間違った道を進んでいる場合、提案は大歓迎です。

16
Fede

動作するはずです。

AsyncLocal<T>は、論理呼び出しコンテキストを抽象化したものです。 論理呼び出しコンテキストとそれがasync/awaitとどのように相互作用するか については、古いブログ投稿で詳しく説明しています。

要約すると、おそらく正常に機能しますが、ThreadStaticとはまったく異なるAsyncLocal<T>の1つの側面があります。

AsyncLocal<T>値に書き込むと、その値が現在の論理呼び出しコンテキストに設定されます。 asyncメソッドは、論理呼び出しコンテキストのコピーオンライトスコープを確立するため、内に書き込むとasyncメソッド、新しい値を含むnew論理呼び出しコンテキストを作成します。これにより、asyncメソッドでネストされた方法で使用できるようになり、「内部」コンテキストが「外部」コンテキストを上書きできます。 ただし、「内部」コンテキスト値が呼び出し元に逆流することはありません。 「外部」コンテキストが再開されると、「内部」コンテキストが完全に置き換えられます。

どのメソッドもasyncでなく、値が独自のスレッドからのみ設定されている場合、そのスレッドには単一の論理呼び出しコンテキストがあり、値の書き込み/読み取りはThreadStatic

22
Stephen Cleary