2009-04-09 22 views
12

用戶點擊全部採用使用的HttpContext的跨線程

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

不要擔心的事實,ASP.Net貌似是向用戶發送頁面spawn.aspx,然後產生一個半打線程,渲染頁面針對1個請求的7個響應,該部分被處理並且僅發送一個響應。

的問題是,在高流量環境(我們的生產環境)具有許多線程(四四芯),我們得到一個錯誤:

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中。我想我還想要其他部分,比如Cache。對於記錄HTTPContext.Current.Session.IsSynchronized爲false。

我的問題是:

  1. 你認爲錯誤的是來自全國各地的線程使用的HttpContext?
  2. 我該如何解決?
  3. 如果修復程序爲每個線程複製HTTPContext,如何將Session(和Cache)獲取到新的線程中?請求和響應進入ctor,但會話不可設置。

編輯:更多詳細信息

所以回到這一說法:「不要擔心的事實,ASP.Net貌似是發送者7個響應爲1個請求,這部分被處理並且只有一個響應被髮送。「雷蒙德巨大的粉絲,我同意你的看法:「現在你有兩個問題」,在沒有更多信息的情況下是合理的陳述。

實際發生的是我正在構建一個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報告只是所有衍生頁面的聚合。)

所以我想通過最終的結果是「你不能做到這一點,你需要重新思考這種方法」 - 但我必須至少嘗試一下,因爲所有事情都能很好地工作,而不會重複任何邏輯或任何代碼,或者不得不抽象任何東西是如此完美。而且這只是多線程問題,如果我連續渲染頁面,一切都很好,只是很慢。

回答

2

你的同事是正確的,如果一個線程鎖定一個資源,另一個線程嘗試使用它,那麼你的線程池繁榮!不是很好的結果。大多數人通過創建新對象並將它們傳遞給參數化線程來解決這個問題。如果你絕對需要使用相同的對象,那麼你必須實現一些代碼,首先檢查是否有資源正在被另一個線程使用,然後再等一會兒再檢查。一個例子是創建一個IsInUse bool,你總是首先檢查,然後你的線程將它設置爲true,如果它正在使用該資源,則在完成時爲false,阻止其他線程嘗試使用底層資源(您的httpContext) 。我希望這有幫助。

+0

這個鎖定可能很難安排,他得到的線程異常是來自Page類,它改變了http上下文,除非他可以重寫頁面中的動作,這樣做,然後放置一個鎖,然後鎖定解決方案將不起作用。 – meandmycode 2009-04-09 22:31:13

4

雖然HttpContext的是專門用來處理非線程特定的(因爲HTTP上下文可以開始一個線程,並完成在另一個)上下文,它不是隱含線程安全的。

本質上問題在於你正在做的事情不是有意的,這些請求通常是多個請求,每個請求都有自己分配的HttpApplication來完成請求,並且每個請求都有自己的HttpContext。

我真的會嘗試讓asp.net基礎架構委託自己的請求。

1

由於HttpContext的是.NET庫的一部分,我希望所有的靜態函數是線程安全的,但對對象的同一實例調用時,任何非靜態成員不是線程安全的。所以希望下次你會預料到跨線程共享HttpContext實例會有問題。

有沒有辦法可以將您需要從HttpContext並行執行的操作分開?如果他們只是加載數據並寫入CSV格式,則該代碼對ASP.NET用戶控件或頁面生命週期沒有必要的依賴。一旦刪除了依賴關係,就可以使用異步HttpHandler實現頁面,在IHttpHandler.BeginProcessingRequest()和IHttpHandler.EndProcessingRequest()之間運行並行操作。

1

我會確保在任何時候訪問HttpContext.Current.Items集合,並使用HttpContext.Current.Items.SyncRoot對象上的Monitor鎖(C#)/ SyncLock(VB)塊來封裝您的調用。