2010-12-15 117 views
8

當我在Global.asax.cs中創建一個空的Session_Start處理程序時,它會在將頁面呈現給瀏覽器時產生重大打擊。爲什麼Global.asax.cs中的Session_Start會導致性能問題?

如何重現:

創建一個空的ASP.NET MVC 3 Web應用程序(我使用MVC 3 RC2)。 然後添加一個首頁控制器與此代碼:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
    return View(); 
    } 
    public ActionResult Number(int id) 
    { 
    return Content(id.ToString()); 
    } 
} 

接下來創建一個視圖主頁/ Index.cshtml並放置在主體部分如下:

@for (int n = 0; n < 20; n++) 
{ 
    <iframe src="@Url.Content("~/Home/Number/" + n)" width=100 height=100 /> 
} 

當你運行這個頁面,你」我們將看到20個IFRAME出現在頁面上,每個IFRAME都在裏面有一個數字。我在這裏所做的就是創建一個頁面,在幕後加載20頁。在繼續之前,請注意這20頁的加載速度有多快(刷新頁面幾次以重複加載)。

接下來去你的Global.asax.cs並添加這個方法(是的,方法體爲空):

protected void Session_Start() 
{ 
} 

現在再次運行該頁面。這次你會注意到20個IFRAME的負載比較慢,一個接一個地相隔約1秒。這很奇怪,因爲我們實際上並沒有在Session_Start中做任何事情......這只是一個空的方法。但這似乎足以導致所有後續頁面的放緩。

有沒有人知道爲什麼會發生這種情況,而且更好的做法是否有人修復/解決方法?

我發現,當調試器附加該行爲只發生更新(按F5運行)。如果你在沒有附加調試器的情況下運行它(Ctrl-F5),那麼它看起來沒問題。所以,也許這不是一個重大的問題,但它仍然很奇怪。

+0

我在SPA應用程序的AJAX請求中遇到了這個問題。指導我遠離使用SessionState。 – voam 2014-01-31 15:03:03

回答

10

TL;博士:如果你面臨這樣的問題,WebForms和不要求在特定頁面的會話狀態寫訪問,添加EnableSessionState="ReadOnly"@Page指令幫助。


顯然,中Session_Start獨力ASP.NET的所有腦幹執行從同一會話順序發出的所有請求。但是,如果您不需要對會話進行寫入訪問(參見下文),則可以逐頁修復此問題。

我用Webforms創建了我自己的測試設置,它使用aspx頁面來傳送圖像。

下面是測試頁面(純HTML,啓動該項目的頁面):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head><title></title></head> 
<body> 
    <div> 
     <img src="GetImage.aspx?text=A" /> 
     <img src="GetImage.aspx?text=B" /> 
     <img src="GetImage.aspx?text=C" /> 
     <img src="GetImage.aspx?text=D" /> 
     <img src="GetImage.aspx?text=E" /> 
     <img src="GetImage.aspx?text=F" /> 
     <img src="GetImage.aspx?text=G" /> 
     <img src="GetImage.aspx?text=H" /> 
     <img src="GetImage.aspx?text=I" /> 
     <img src="GetImage.aspx?text=J" /> 
     <img src="GetImage.aspx?text=K" /> 
     <img src="GetImage.aspx?text=L" /> 
    </div> 
</body> 
</html> 

這裏的aspx頁面(GetImage.aspx):

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetImage.aspx.cs" Inherits="CsWebApplication1.GetImage" %> 

及相關零部件的代碼隱藏(GetImage.aspx.cs,usingnamespace跳過):

public partial class GetImage : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     Debug.WriteLine("Start: " + DateTime.Now.Millisecond); 
     Response.Clear(); 
     Response.ContentType = "image/jpeg"; 

     var image = GetDummyImage(Request.QueryString["text"]); 
     Response.OutputStream.Write(image, 0, image.Length); 
     Debug.WriteLine("End: " + DateTime.Now.Millisecond); 
    } 

    // Empty 50x50 JPG with text written in the center 
    private byte[] GetDummyImage(string text) 
    { 
     using (var bmp = new Bitmap(50, 50)) 
     using (var gr = Graphics.FromImage(bmp)) 
     { 
      gr.Clear(Color.White); 
      gr.DrawString(text, 
       new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular, GraphicsUnit.Point), 
       Brushes.Black, new RectangleF(0, 0, 50, 50), 
       new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); 
      using (var stream = new MemoryStream()) 
      { 
       bmp.Save(stream, ImageFormat.Jpeg); 
       return stream.ToArray(); 
      } 
     } 
    } 
} 

測試運行

  • 運行1,不變:將頁面加載速度快,輸出窗口顯示的StartEnd個隨意的搭配,這意味着該請求得到並行處理。

  • 運行2,加空Session_Startglobal.asax(需要在瀏覽器一旦按下F5,不知道這是爲什麼):StartEnd交替,顯示出請求得到sequentually處理。多次刷新瀏覽器表明,即使未連接調試器,也會出現性能問題。

  • 運行3,如試驗2,但添加EnableSessionState="ReadOnly"@Page指令GetImage.aspx:第一End之前調試輸出顯示多個Start秒。我們再次平行,我們有良好的表現。


是的,我知道,這應該與一個ASHX處理程序來完成吧。這只是一個例子。

+0

有趣的...你能測試當你在調試器外部運行這些測試時發生了什麼(即用Ctrl-F5而不是F5啓動) – Mike 2012-03-01 16:40:07

+0

@Mike:我做到了。即使沒有調試器,運行2也比其他調試器慢(與調試器不同,但它仍然很明顯)。 – Heinzi 2012-03-01 22:53:05

3

不能告訴你你的調試器在做什麼(intellitrace?詳細日誌記錄?第一次機會異常?),但是你仍然掌握了處理併發請求的能力。

訪問ASP.NET會話狀態是每個會話獨佔的,這意味着如果兩個不同的用戶發出併發請求,則同時授予對每個單獨會話的訪問權限。 但是,如果爲同一會話(通過使用相同的SessionID值)提出兩個併發請求,則第一個請求將獲得對會話信息的獨佔訪問權限。第二個請求僅在第一個請求完成後執行。(如果由於第一個請求超過了鎖定超時而對信息的排他鎖被釋放,第二個會話也可以訪問。)如果@ Page指令中的EnableSessionState值設置爲ReadOnly,只有會話信息不會導致對會話數據的獨佔鎖定。但是,會話數據的只讀請求可能仍然需要等待由會話數據的讀寫請求設置的鎖定清除。

來源:ASP.NET Session State Overview,我的重點

+0

這很有趣,但我不認爲它解釋了上述行爲。案例#1和案例#2之間的唯一區別是Global.asax.cs中存在空的Session_Start方法。根據你的參考,這兩種情況應該仍然表現相同。 – Mike 2011-05-10 13:34:45

+0

顯然,Global.asax.cs中的空Session_Start方法足以使ASP.NET序列化請求。我遇到了與Webforms類似的問題,並發現它可以通過在爲並行頁面提供服務的aspx頁面的@ Page指令中設置EnableSessionState =「ReadOnly」來解決(我的例子中是圖片)。我不知道MVC是否存在類似的選項。 – Heinzi 2012-02-14 16:11:03

+0

@Heinzi非常有趣!你有任何文件/證據顯示這種行爲?如果是這樣,請創建一個新答案,並將其標記爲已接受。 – Mike 2012-02-14 21:33:10

相關問題