2010-12-15 9 views
8

Wenn ich einen leeren Session_Start-Handler in Global.asax.cs erstellen, verursacht dies einen erheblichen Treffer beim Rendern von Seiten im Browser.Warum verursacht Session_Start in Global.asax.cs Leistungsprobleme?

Wie zu reproduzieren:

Erstellen Sie eine leere ASP.NET MVC 3 Web-Anwendung (I MVC 3 RC2 verwende). Dann eine Heimsteuerung mit diesem Code hinzufügen:

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

nächstes eine Ansicht Home/Index.cshtml erstellen und die folgenden im BODY-Abschnitt platzieren:

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

Wenn Sie diese Seite nicht ausführen, Sie‘ ll sehen 20 IFRAMEs erscheinen auf der Seite, jede mit einer Zahl darin. Alles, was ich hier mache, ist eine Seite zu erstellen, die 20 weitere Seiten hinter den Kulissen lädt. Bevor Sie fortfahren, notieren Sie, wie schnell diese 20 Seiten geladen werden (aktualisieren Sie die Seite einige Male, um die Ladevorgänge zu wiederholen).

Neben Ihrem Global.asax.cs gehen und fügen Sie diese Methode (ja, das Verfahren Körper ist leer):

protected void Session_Start() 
{ 
} 

nun wieder die Seite auszuführen. Dieses Mal werden Sie feststellen, dass die 20 IFRAMEs viel langsamer geladen werden, eine Sekunde nach der anderen. Das ist seltsam, weil wir in Session_Start eigentlich nichts machen ... es ist nur eine leere Methode. Aber das scheint genug zu sein, um die Verlangsamung in allen folgenden Seiten zu verursachen.

Weiß jemand, warum das passiert, und besser noch hat jemand eine Lösung/Workaround?

aktualisieren

ich, dass dieses Verhalten tritt nur entdeckt haben, wenn der Debugger (mit F5 ausgeführt wird) angebracht ist. Wenn Sie es ohne den angehängten Debugger (Strg-F5) ausführen, scheint es in Ordnung zu sein. Also, vielleicht ist es kein großes Problem, aber es ist immer noch seltsam.

+0

Ich stieß auf dieses Problem auf AJAX-Anfragen in einer SPA-Anwendung. Hat mich davon abgehalten, SessionState zu benutzen. – voam

Antwort

10

tl; dr: Wenn Sie stellen dieses Problem mit Webforms und Schreibzugriff auf den Sitzungszustand nicht in dieser bestimmten Seite erfordern, das Hinzufügen EnableSessionState="ReadOnly" zu Ihrer @Page Richtlinie hilft.


Offenbar ist die Existenz von Session_Start allein ASP.NET Kräfte alle Anforderungen auszuführen aus der gleichen Session sequentiell stammen. Dies kann jedoch Seite für Seite behoben werden, wenn Sie keinen Schreibzugriff auf die Sitzung benötigen (siehe unten).

Ich habe meine eigene Testeinstellung mit Webforms erstellt, die eine ASPX-Seite verwendet, um Bilder zu liefern. 1

Hier ist die Testseite (einfache HTML-Seite des Projektes beginnen):

<!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> 

Hier sind die aspx Seite (GetImage.aspx):

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

Und die relevanten Teile des Codebehinds (GetImage.aspx.cs, using und namespace übersprungen):

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

Testläufe

  • Lauf 1, unmodifizierten: Die Seite lädt schnell, das Ausgabefenster eine zufällige Mischung aus Start und End s zeigt, was bedeutet, dass die Anforderungen parallel verarbeitet bekommen.

  • Run 2, fügen leer Session_Start-global.asax (müssen F5 einmal im Browser schlagen, weiß nicht, warum das so ist): Start und End wechseln sich ab, was zeigt, dass die Anfragen sequentually verarbeitet bekommen. Wenn Sie den Browser mehrmals aktualisieren, zeigt dies, dass dies Leistungsprobleme hat, selbst wenn der Debugger nicht angeschlossen ist.

  • Run 3, wie Run 2, aber fügen Sie EnableSessionState="ReadOnly" auf die @Page Richtlinie von GetImage.aspx: Die Debug-Ausgabe zeigt mehr Start s vor den ersten End. Wir sind wieder parallel und wir haben eine gute Leistung.


Ja, ich weiß, dass dies stattdessen mit einem Ashx Handler getan werden soll. Es ist nur ein Beispiel.

+0

Interessant ... können Sie testen, was passiert, wenn Sie diese Tests außerhalb des Debuggers ausführen (d. H. Mit Strg-F5 anstelle von F5 starten) – Mike

+0

@Mike: Ich tat es. Run 2 ist langsamer als die anderen, sogar ohne den Debugger (der Unterschied ist nicht so stark wie beim Debugger, aber es ist immer noch bemerkbar). – Heinzi

3

Kann Ihnen nicht sagen, was Ihr Debugger macht (intellitrace? Detaillierte Protokollierung? First-Chance-Ausnahmen?), Aber Sie sind immer noch in den Händen der Sitzungen Fähigkeit, gleichzeitige Anfragen zu behandeln.

Der Zugriff auf den ASP.NET-Sitzungsstatus ist pro Sitzung exklusiv, dh wenn zwei verschiedene Benutzer gleichzeitig Anfragen stellen, wird der Zugriff auf jede einzelne Sitzung gleichzeitig gewährt. Wenn jedoch zwei gleichzeitige Anforderungen für dieselbe Sitzung (mit demselben SessionID-Wert) gestellt werden, erhält die erste Anforderung exklusiven Zugriff auf die Sitzungsinformationen. Die zweite Anfrage wird erst ausgeführt, nachdem die erste Anfrage beendet wurde. (Die zweite Sitzung kann auch Zugriff erhalten, wenn die exklusive Sperre für die Informationen aufgehoben wird, da die erste Anforderung das Sperrzeitlimit überschreitet.) Wenn der EnableSessionState-Wert in der @ Page-Direktive auf ReadOnly gesetzt ist, wird eine Anforderung für das Lesen angefordert. Nur Sitzungsinformationen führen nicht zu einer exklusiven Sperre der Sitzungsdaten. Es ist jedoch möglich, dass schreibgeschützte Anforderungen für Sitzungsdaten immer noch auf eine Sperre warten müssen, die durch eine Lese-/Schreibanforderung zum Bereinigen von Sitzungsdaten festgelegt wurde.

Quelle: ASP.NET Session State Overview, mein Schwerpunkt

+0

Das ist interessant zu wissen, aber ich denke nicht, dass es das oben beschriebene Verhalten erklärt. Der einzige Unterschied zwischen Fall Nr. 1 und Fall Nr. 2 ist das Vorhandensein einer leeren Methode Session_Start in Global.asax.cs. Laut Ihrer Referenz sollten sich beide Fälle immer noch gleich verhalten. – Mike

+0

Anscheinend reicht eine leere 'Session_Start'-Methode in Global.asax.cs aus, um ASP.NET-Serialisierungsanforderungen auszuführen. Ich hatte ein ähnliches Problem mit Webforms und festgestellt, dass es behoben werden kann, indem Sie 'EnableSessionState =" ReadOnly "' in der '@ Page'-Direktive der Aspx-Seite, die die parallelen Seiten (Bilder in meinem Fall) bedient. Ich weiß nicht, ob eine ähnliche Option für MVC existiert. – Heinzi

+0

@Heinzi Sehr interessant! Haben Sie Unterlagen/Beweise, die dieses Verhalten zeigen? Wenn ja, bitte erstellen Sie eine neue Antwort und ich werde es als akzeptiert markieren. – Mike