13

ユーザーがページspawn.aspxにアクセスすると、半ダースのスレッドが生成され、すべてのページが

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

ASP.Netがユーザーに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が複製されている場合、セッション(およびキャッシュ)を新しいスレッドに取り込むにはどうすればよいですか?リクエストとレスポンスはコンストラクターで行われますが、セッションは設定できません。

編集:詳細

したがって、このステートメントに戻ります。「ASP.Netがユーザーに1つの要求に対して7つの応答を送信しているように見え、その部分が処理され、1つの応答のみが送信されるという事実について心配する必要はありません。」レイモンド・チェンの大ファン、私はあなたに同意します:「今あなたは2つの問題を抱えています」はこれ以上の情報がない場合の合理的な声明です。

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

 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);
 }

しかし、それまでのすべての処理-データベースアクセス、制御階層、すべてが並行して実行されます。そして、それはたくさんあります-それでもRenderでブロックさせながらそれを並列化すると、全体の時間が半分以上に短縮されます。

そして、その最良の部分は、Excelレンダリングのために何も書き直す必要がなかったことです。すべてのコントロールは、Excelをレンダリングする方法を知っており、生成された各ページに個別にアクセスできます(これは、実際には「通常のケース」です。Excelレポートは、生成されたすべてのページの単なる集約です)。

したがって、最終結果は「これはできません。アプローチを再考する必要があります」になると思いましたが、ロジックやコードを複製することなくすべてがうまく機能するという事実から、少なくとも試してみる必要がありました。何かを抽象化する必要があるのはとても完璧です。そして、問題となるのはマルチスレッドだけです。ページをシリアルにレンダリングすると、すべてが正常になり、遅くなります。

4

4 に答える 4

4

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

基本的に問題は、意図していないことをしていることです。これらのリクエストは一般的に複数あり、それぞれにリクエストを満たすために独自の HttpApplication が割り当てられ、それぞれに独自の HttpContext があります。

私は本当に asp.net インフラストラクチャにリクエスト自体を委任させようとします。

于 2009-04-09T22:29:36.357 に答える
2

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

于 2009-04-09T15:57:35.580 に答える
1

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

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

于 2009-04-11T03:29:26.437 に答える
1

HttpContext.Current.Items コレクションにアクセスするときはいつでも、HttpContext.Current.Items.SyncRoot オブジェクトで Monitor lock (C#)/SyncLock(VB) ブロックを使用して呼び出しをラップするようにしてください。

于 2011-02-27T04:00:31.393 に答える