2016-12-07 2 views
2

吊り下げに問題がありました(hereを参照)。研究中にSetResultTaskCompletionSourceに呼び出すと、実際にSetResultというスレッドのコンテキストで待機中の継続が呼び出されていることがわかりました(これはthis answerという質問に多少関連しています)。私の場合、これはawait(ASP.NETリクエストスレッド)を開始したスレッドとは別のスレッド(スレッドプールワーカースレッド)です。タスクを完了したときにSynchronizationContextを手動でキャプチャして適用する

これがなぜハングアップするのかまだわかりませんが、私はSetResultを元のコンテキストに強制しようとしました。リクエストスレッドにawaitを入力する前にSynchronizationContext.Currentの値を保存し、SynchronizationContext.SetSynchronizationContextを介して手動でワーカースレッドに適用したところ、SetResultを呼び出す直前です。これによりハングが解消され、ConfigureAwait(false)を指定せずにすべての非同期メソッドを待つことができます。

私の質問は、SynchronizationContextを手動でキャプチャして適用するのに合理的かつ正しいアプローチですか? FWIW、私はSetResultデリゲートで簡単にPost()を実行しようとしましたが、それでもハングしました。私は明らかにここの私の快適ゾーンから少し外れています...何が起こっているのか理解してください!

答えて

0

、私は完全に私のHTTPハンドラが非同期ハンドラのサポートを追加するために非常に疑わしい方法でIAsyncHttpHandlerを実施し、小さな基底クラスから派生したことを見落としていました:

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) 
{ 
    ... 
    var task = HandleRequestAsync(...); 

    Task.Run(async() => { await task; }).GetAwaiter().GetResult(); 
    ... 
} 

私ができますなぜ私が最初にこれをやったのか覚えていない(それは1年以上前だった)が、間違いなく私が最後の数日間探していた愚かな部分!

ハンドラー基本クラスを.NET 4.6のHttpTaskAsyncHandlerに変更すると、ハングアップがなくなりました。みんなの時間を無駄にして申し訳ありません! :(

3

SetResultは何も呼び出すことはできません。したがって、これは信頼できません。

キャプチャされた時点で同期コンテキストを切り替える必要があります。一般的な問題点は、Webリクエストを開始するときにコンテキストを取得するWebClientです。したがって、あなたのコードは次のようになります。

SetContext(newContext); 
new WebClient().DownloadAsync(...); 
SetContext(oldContext); 

何も妨害しないように古いコンテキストを復元します。

つまり、問題は継続コードであり、コードSetResultではありません。私の恥ずかしさに

+0

SetResult(またはその欠如)の保証について...少し拡大できますか?*観察された効果は、手動で適用されたコンテキストがワーカースレッドあなたが暗示しているように、私は荒々しい詳細についてもっと知りたいと思っています! – aoven

+0

TPLにはいくつかのポイントがありますスレッドのローカルステートを変更し、このコールチェーンを持っている場合:A => SetResult => Bならば、Bはそのステートを参照します。もしチェーンがA => SetResult => QueueToThreadPool(B)ならば、Bはクリーンな状態を見るでしょう。これはあなたが見ていることを説明していますか?= – usr

+0

私は確実にどちらかの方法を言うことができません...私のチェーンは実際にはA => QueueToThreadPool => SetResult => Bであり、コールが成功しワーカースレッドがブロックされないため、SetResultが継続を直接呼び出さないと判断しました。ブロックされている唯一のもの(私には目に見える)は待っています。RunContinuationsをTaskCompletionSourceと同時に渡すと、Post/Sendを呼び出すのと同じように効果がないようです。 あなたは以前に問題が継続していると言いました...実行されることがないと(ブロックは待っている回線で発生します)、どんな種類の問題が起こる可能性がありますか? – aoven

関連する問題