如果在兩個瀏覽器中,開啟同一個web系統的兩支asp.net程式,這2支程式會並存執行嗎?
那麼在一個瀏覽器中開啟這兩支程式呢?
第一種情況,可能很容易就知道是並行的,因為不管IE還是chrome,或是其它瀏覽器,在一個視窗中,一般都是共用一個session,因此這種情況,和兩台不同的機器的請求應該是一樣的。
然而對於第二種,情況就不那麼簡單了。
先做個簡單的實驗
1.建立web月台,增加a.aspx和b.aspx
a.aspx:
<%@ Page Language="C#" %>
<%
System.Threading.Thread.Sleep(10000); //睡10秒,在這個長時間的執行過程中,還容得下其它請求嗎?
%>
Hello,A.aspx
b.aspx:
<%@ Page Language="C#" %>
<%
Session["TestKey"] = "test";
%>
Hello,B.aspx
2.開啟IE8,用兩個Tab,分別瀏覽a.aspx和b.aspx
結果很明顯,asp.net對於同一個Session,居然是單線程執行,到底發生了什嗎?
可能眼尖的TX,發現了在b.aspx中,有一行代碼似乎很紮眼
Session["TestKey"] = "test";
為什麼要加這一行?不加會怎麼樣?
你猜得沒錯,不加就是並存執行,任你第一個的執行時間再怎麼長,我第二個都會側著身子,全身而退。
注釋這行代碼測試一下,不過記得關掉剛才那個視窗,重新開啟一個(因為剛才那個視窗已寫入了Session的Cookie值,所以asp.net還是認為是有Session存在的)
到這裡,結論好像很簡單了,對於同一個Session,asp.net單線程執行。
找找原因
翻出.net 原始碼,在System.Web.State.InProcStateClientManager的DoGet方法中找到了關鍵代碼
圖中可以看出state對象,一定會被某次session的第一個request給鎖住,
同一個session的其它request,你就慢慢等著第一個執行完再解鎖吧
繼續~
被鎖後SessionStateModule的GetSessionStateItem方法返回locked為true
isCompleted自然就設定為false了,而BeginAcquireState方法的_rqAr.CompletedSynchronously也就沒機會調用Complete方法改為true
因此HttpApplication,也就沒辦法執行這次請求的後半段(_endHandler),也就是aspx頁的代碼了,這也是我們測試時第二個請求在等第一個請求完成的原因
最後結論,asp.net中如果用了Session,就別想並存執行了,雖然很多時候,並不會有什麼問題,但是對於ajax程式來說,用戶端費盡心思的的多個非同步請求,也變成了笑話,因為伺服器端實際上還是one by one在執行,就算你發再多請求過去又有什麼用,使用者還是:
我等得花兒也謝了~
PS:找到原因後也很慶幸,現在開發的架構和制定的規範,裡面除了個別地方為了提高效能以外,其它任何地方都禁止使用session,永遠為用戶端提供無狀態,可重新進入的http服務,保證可靠的web調用