近日在對一個ASP.NET WEBFORM項目進行調優過程當中,偶然發現頁面POSTBACK事件是串行處理的,甚至不一樣頁面的請求都是串行處理的(一個頁面加載完畢後,纔開始加載第二個頁面)。可是網站明明是併發處理請求的啊,當時十分不解,把代碼翻來覆去排查了大半天,尋找業務框架中什麼地方是否是鎖了資源。各類斷點、調試、日誌所有用上,仍是找不到緣由。
仔細思考了一下,ASP.NET確定不會是串行處理的,難道是某一個Session中,ASP.NET對其串行處理請求?瀏覽器
在項目中新增一個頁面,只能加最簡單的事件代碼:session
log.Info("start"); System.Threading.Thread.Sleep(5000); log.Info("end");
瀏覽器中開打兩個標籤頁同時訪問該頁面,結果請求時並行處理的。併發
16:24:44[9]start 16:24:45[10]start 16:24:49[9]end 16:24:50[10]end
接着先訪問下登錄頁面,而後再重複上次動做,請求變成串行處理了!框架
16:26:11[9]start 16:26:16[9]end 16:26:16[10]start 16:26:21[10]end
換成兩個瀏覽器,分別登錄後訪問該頁面,請求被並行處理。
自此確認確定是SESSION的問題!網站
GOOGLE搜索了一番,找到緣由及解決方案:調試
The session state module implements a locking mechanism and queues the access to state values. A page that has session-state write access will hold a writer lock on the session until the request finishes. A page gains write access to the session state by setting the EnableSessionState attribute on the @Page directive to True. A page that has session-state read access -- for example, when the EnableSessionState attribute is set to ReadOnly -- will hold a reader lock on the session until the request finishes.日誌
原來SessionStateModule模塊實現了一個寫入鎖,並對其進行排隊處理,因此同一SESSION下的全部請求都會被串行執行。事件
解決方案也很簡單,在頁面上增長EnableSessionState="ReadOnly"指令便可。 固然,增長了這個指令後,這個頁面也就不能修改SESSION值了。資源
GOOGLE的過程當中,發現.NET MVC一樣也有這個問題,其解決方案是在controller上增長特性[SessionState(SessionStateBehavior.ReadOnly)]
隨手實驗一番,不加以上特性時,在有SESSION的狀況下,同SESSION的請求會被串行處理。增長SessionStateBehavior.ReadOnly後不一樣action中,請求會被並行處理,可是相同action仍然是串行處理的。
即便是Task<ActionResult>
,任然沒法逃脫串行執行的魔掌。