2009-04-09 10 views
12

ユーザーはページその後、ページのレンダリング、半ダースのスレッドを生成spawn.aspxすべてのASP.Netは一見のユーザーに送信しているという事実を心配しないでください使用のHttpContextは、スレッド間で

((System.Web.IHttpHandler)instance).ProcessRequest(reference to spawn's HTTPContext); 

を使用してのヒット1つの要求に対する7つの応答、その部分が処理され、1つの応答のみが送信されます。

System.IndexOutOfRangeException 
at System.collections.ArrayList.Add 
at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, DateTime utcDepTime) 
at System.Web.ResponseDependencyList.AddDependencies(String[] items, String argname, Boolean cloneArray, String requestVritualPath) 
at System.Web.UI.Page.AddWrappedFileDependencies(Object virtualFileDependencies) 
at ASP.spawned_page_no_1_aspx.FrameworkInitialize() 
at System.Web.UI.Page.ProcessRequest 

我々は他の場所でそれを複製することはできません。

は問題があり、多くのスレッド(クワッドクワッド)と高トラフィック的環境(当社の生産的環境)で、私たちはエラーが発生します。私の同僚は、元のHTTPContextを再利用して他のスレッドに渡し、スレッドセーフではないため、これが原因だと考えています。

このロジックに続いて、新しいHTTPContextをスレッドに渡すように試みました。しかし、その部分は一見「結合」しません。具体的には、Sessionオブジェクトを新しいHTTPContextに取得する必要があります。私は、キャッシュのように他の部品も手に入れたいと思っています。レコードのHTTPContext.Current.Session.IsSynchronizedはfalseです。

私の質問は以下のとおりです。

  1. エラーがスレッド間のHttpContextを使用してからだと思いますか?
  2. どうすれば修正できますか?
  3. 修正によって各スレッドのHTTPContextが複製されている場合、どのように新しいものにSession(およびCache)を取得できますか?要求と応答はctorに入っていますが、セッションは設定できません。

編集:詳細を

だから戻って、この声明に行く:「ASP.Netは一見、ユーザ1つの要求のための7つのレスポンスを送信していますが、その部分が処理されていることを心配しないでください1つの応答のみが送信されます。レイモンド・チェンの巨大なファン、私はあなたに同意する: "今あなたは2つの問題がある"は、それ以上の情報がない場合、合理的な声明です。

実際に起こっていることは、返信するExcelドキュメントを作成していることです。 spawn.aspxページでは、それが優れたレンダリングであること、レンダリングを行うオブジェクトなど、いくつかの状態情報を設定しています。スポーンされた各ページはその情報を取得し、オブジェクトにレンダリングする順番になるまでブロックします。文字通り、このようになります場合:

protected override void Render(System.Web.UI.HtmlTextWriter writer) 
{ 
    if (this.RenderToExcel) 
    { 
     Deadlocker.SpinUntilCurrent(DeadLockToken); 
     RenderReport(this, this.XLSWriter); 
     Deadlocker.Remove(DeadLockToken); 
    } 
    else 
     base.Render(writer); 
} 

しかし、すべてのそれまでの処理 - データベースアクセス、制御階層構造、すべてのことが並行して行われます。そして、たくさんのことがあります。レンダリングでそれをブロックさせながら、それをparrallizeすれば、全体の時間が半分になります。

そして、Excelのレンダリングには何も書き直す必要はありません。すべてのコントロールは自分自身を優れたものにする方法を知っていて、独立した各ページを個別に訪問することができます(実際には正常なケース - 実際にはすべてのスポンサーページの集合です)。 「あなたはこれを行うことはできません。アプローチを再考する必要があります」 - しかし、少なくとも論理的にもコードも複製したり、抽象化することなくすべてがうまく動作するという事実ちょうど完璧です。そして、それが問題であるだけのマルチスレッドです。すべてのページを連続的にレンダリングすれば、すべてがうまく、遅くなります。

答えて

2

あなたの同僚は正しいです、あるスレッドがリソースをロックし、別のスレッドがそれを使用しようとすると、スレッドプールがブームになります!あまり良い結果はありません。ほとんどの人は、新しいオブジェクトを作成し、それをparamaterizedスレッドに渡すことでこれを解決します。同じオブジェクトを絶対に使用する必要がある場合は、リソースが別のスレッドによって使用されているかどうかを最初に確認し、再度チェックする前に少し待っているコードを実装する必要があります。最初にチェックするIsInUse boolを作成し、そのリソースを使用している場合はスレッドをtrueに設定し、完了したらfalseに設定して、他のスレッドが基になるリソース(httpContext)を使用しようとしないようにします。 。私はこれが役立つことを願っています

+0

Alこのロックはおそらく手配するのが難しいでしょう。彼が得ているスレッド例外は、これを行っているページのアクションをオーバーライドできない限り、httpコンテキストを変更しているページクラスからですロックソリューションは動作しません。 – meandmycode

+1

素晴らしいコメント、私はあなたに同意します。私の好みは、トレッドの作成時にHTTPコンテキストからその情報の一部を派生させる完全に新しいオブジェクトを渡すことです。それは弾丸であろう。 –

4

HttpContextはスレッド固有ではないコンテキストを処理するように設計されていますが(HTTPコンテキストはあるスレッドで開始して別のスレッドで終了することができるため)、暗黙的にスレッドセーフではありません。

本質的に問題は、意図しない何かをしているということです。これらの要求は一般的に複数あり、それぞれが独自の割り当てられたHttpApplicationを持っており、それぞれが独自のHttpContextを持っています。

私は実際にasp.netインフラストラクチャに要求自体を委任させようとします。

1

HttpContextは.Netライブラリの一部なので、すべての静的関数はスレッドセーフですが、静的でないメンバーはオブジェクトの同じインスタンスに対して呼び出すときにスレッドセーフではありません。次回は、スレッド間でHttpContextインスタンスを共有すると問題が発生することが予想されます

HttpContextから並列に実行する必要がある操作を切り離す方法はありますか?データをロードしてCSV形式に書き込むだけの場合、そのコードはASP.NETユーザーコントロールまたはページライフサイクルに依存する必要はありません。その依存関係が削除されたら、IHttpHandler.BeginProcessingRequest()とIHttpHandler.EndProcessingRequest()の間で並列操作を実行し、非同期HttpHandlerを使用してページを実装できます。

1

HttpContext.Current.Itemsコレクションにアクセスするたびに、HttpContext.Current.Items.SyncRootオブジェクトでMonitor lock(C#)/ SyncLock(VB)ブロックを使用して呼び出しをラップすることを確認します。