3

ASP.NETの上に構築されたさまざまなWebサービス用のかなり大きな既存のコードベースがあり、そのコードはアクセスを多用しますHttpContext.Current.User( としてラップされます)。これは、アンビエントスコープを提供するためにClient.User内部的に使用されると確信しています。[ThreadStatic]

の形式でより多くの非同期コードを使用し始める可能性があるかどうかを現在調べていますが、 の使用がこれにどのように適合するasync/awaitかを見つけるのに苦労しています。[ThreadStatic]頻繁に使用されるため、依存を取り除くこと[ThreadStatic]は実際には不可能です。

awaitがヒットすると、コードの実行がそこで停止し、呼び出しがすぐに返され、非同期コードが返されたときに実行を継続するように継続が設定されていることを理解しています。一方、元のスレッドは、別の要求を処理するなど、他の用途に自由に使用できます。ここまでは私の理解です。

決定的な答えが本当に見つからないHttpContext.Current.Userのは、 が の前後で同じであることが保証されているかどうかawaitです。

だから基本的に:

HttpContext.Current.User = new MyPrincipal();
var user = HttpContext.Current.User;

await Task.Delay(30000);

// Meanwhile, while we wait for that lots of other requests are being handled, 
// possibly by this thread.

Debug.Assert(object.ReferenceEquals(HttpContext.Current.User, user));

それはDebug.Assert成功することが保証されていますか?

Task.Delay別のリクエストが保留中と同じスレッドによって処理された場合、そのリクエストは別HttpContext.Current.Userの を設定するので、継続が呼び出されたときに以前の状態が何らかの方法で保存および復元されますか?


私が想像できるのは、舞台裏で[ThreadStatic]状態がスレッド自体のある種の辞書として保持され、スレッドがその辞書に戻った後にスレッドプールに戻ると、awaitその辞書はどこかに安全に保管され、スレッドに戻されるということです。それは継続を実行します(またはスレッド上で、継続を処理するのが必ずしも同じスレッドであるかどうかはわかりません)。一部は私の想像にすぎないかもしれません。

それはある程度正確ですか?

更新:これを試みる小さなテストをまとめようとしました。これまでのところ、機能しているようで、何百ものリクエストのうち、アサーションが失敗したことはありません。テストが理にかなっていることを誰でも確認できますか?

https://gist.github.com/anonymous/72d0d6f5ac04babab7b6

4

3 に答える 3

1

ThreadStatic 自体は、非同期コードとまったく相容れないものではありません。各スレッドに特定のオブジェクトの独自のコピーを与えて競合を排除することにより、そのコンテキストでパフォーマンスを向上させるためによく使用されます。

もちろん、慎重に使用する必要があります。また、コードが実行されるスレッドに関係なく同じオブジェクト インスタンスを使用する必要があるシナリオがある場合、ThreadStatic は機能しないか、実行の各フローが確実に行われるようにスレッドを慎重に処理する必要があります。それが属するスレッドに戻ります。

一部のasync/await シナリオでは、元の await と同じスレッドで継続が発生することが保証されます。たとえば、フォームまたは WPF プログラムの GUI スレッド内から待機する場合です。しかし、これは一般的に async/await 機能によって保証されていません。

最終的には、async/await で ThreadStatic を使用できますが、特定の値またはオブジェクトを特定のスレッドに結び付けるという意味で使用していることを確認する必要があります。これは、継続される可能性のある特定の実行フローが、実際にどのオブジェクトを使用するかを気にしない汎用オブジェクトに最適です。または、実行の流れが特定のスレッドにとどまることが確実な場合。

しかし、そうでなければ、いいえ。実行フローで常に同じオブジェクトを使用する必要があるシナリオでは ThreadStatic を使用したくありませんが、実行フローが同じスレッドに留まる保証はありません。(最後の文が明白に思われる場合は申し訳ありません...明確にしたいだけです)。

于 2014-10-22T20:50:31.557 に答える
1

awaitが非同期対応の呼び出しスタック (非同期コントローラー/ハンドラー) から呼び出されたと仮定すると、アサートは成功することが保証されます。

ASP.NET SynchronizationContext は、リターン スレッドで HttpContext を使用できるようにする処理を行います ( を使用しない場合ConfigureAwait(false))。ただし、これは一般にスレッド データには適用されないため、そのタイプの「グローバルなリクエスト」状態がある場合は HttpContext.Items を優先してください。

于 2014-10-22T21:04:29.950 に答える