Pourquoi la Session commence-t-elle dans Global?asax.cs cause des problèmes de performance?

quand je crée un handler session_start vide dans Global.asax.cs il provoque une importante frappé lors du rendu des pages dans le navigateur.

comment reproduire:

créer un vide ASP.NET application web MVC 3 (j'utilise MVC 3 RC2). Ensuite, ajoutez un contrôleur Home avec ce code:

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

suivant créer une vue Accueil/Index.cshtml et placer ce qui suit dans la section corps:

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

quand vous lancez cette page, vous verrez 20 IFRAMEs apparaître sur la page, chacune avec un numéro à l'intérieur. Tout ce que je fais ici, c'est créer une page qui charge 20 pages de plus dans les coulisses. Avant de continuer, prenez note de la vitesse à laquelle ces 20 pages se chargent (rafraîchissez la page quelques fois pour répéter les charges).

ensuite, allez à votre Global.asax.cs et ajouter cette méthode (oui, le corps de la méthode est vide):

protected void Session_Start()
{
}

relancez la page. Cette fois, vous remarquerez que le 20 IFRAMEs chargent beaucoup plus lentement, l'un après l'autre environ 1 seconde d'écart. C'est étrange parce que nous ne faisons rien dans Session_Start ... c'est juste une méthode vide. Mais cela semble suffisant pour causer le ralentissement dans toutes les pages suivantes.

est-ce que quelqu'un sait pourquoi cela se produit, et mieux encore est-ce que quelqu'un a une solution/solution?

mise à Jour

j'ai découvert que ce comportement ne se produit que lorsque le débogueur ci-joint (en cours d'exécution avec la touche F5). Si vous l'exécutez sans le débogueur attaché (Ctrl-F5) alors il semble que ce soit correct. Donc, peut-être que ce n'est pas un problème significatif mais c'est quand même étrange.

9
demandé sur Charles 2010-12-15 18:41:24

2 réponses

tl;dr : si vous rencontrez ce problème avec les formulaires Web et que vous n'avez pas besoin d'un accès en écriture à l'état de session dans cette page particulière, ajouter EnableSessionState="ReadOnly" à votre directive @Page aide.


apparemment, l'existence de Session_Start seules forces ASP.NET pour exécuter toutes les requêtes provenant de la même Session de façon séquentielle. Ceci, cependant, peut être corrigé page par page si vous n'avez pas besoin d'un accès en écriture de la session (voir ci-dessous).

j'ai créé mon propre réglage de test avec des Webforms, qui utilise une page aspx pour livrer des images. 1

Voici la page test (HTML simple, page de début du projet):

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

Voici la page aspx (GetImage.aspx):

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

et les parties pertinentes du codebehind (GetImage.aspx.cs, using et namespace skipped):

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

essais

  • Exécuter 1 , non modifié: la page se charge rapidement, la fenêtre de sortie affiche un mélange aléatoire de Start et End s, ce qui signifie que les requêtes sont traitées en parallèle.

  • Run 2 , ajouter vide Session_Start à global.asax (besoin de frapper F5 une fois dans le navigateur, je ne sais pas pourquoi il en est): Start et End autre, en montrant que les requêtes seront traitées sequentually. Actualisation du navigateur plusieurs fois montre que cela a des problèmes de performances, même lorsque le débogueur n'est pas attaché.

  • Run 3 , comme Run 2, mais ajouter EnableSessionState="ReadOnly" à la directive @Page de GetImage.aspx : la sortie de débogage affiche multiple Start s avant la première End . Nous sommes à nouveau parallèles, et nous avons de bonnes performances.


1 Oui, je sais que cela devrait être fait avec un manipulateur ashx à la place. C'est juste un exemple.

12
répondu Heinzi 2012-02-15 09:06:37

ne peut pas vous dire ce que fait votre débogueur (intellitrace? un enregistrement détaillé? exceptions de la première chance?), mais vous êtes toujours dans les mains des séances de capacité à gérer les demandes simultanées.

accès à ASP.NET l'état de session est exclusif par session, ce qui signifie que si deux utilisateurs différents font des requêtes concurrentes, l'accès à chaque session séparée est accordé simultanément. toutefois, si deux requêtes concurrentes sont présentées pour le même session (en utilisant la même valeur de SessionID), la première demande obtient un accès exclusif aux informations de la session. La seconde requête n'est exécutée qu'après la fin de la première requête. (la deuxième session peut également avoir accès si le verrouillage exclusif sur l'information est libéré parce que la première demande dépasse le temps de verrouillage.) Si la valeur EnableSessionState dans la directive @ Page est définie en lecture seule, une demande d'informations de session en lecture seule n'entraîne pas une exclusion verrouillage sur les données de la session. Cependant, les requêtes en lecture seule pour les données de session peuvent toujours attendre un verrouillage défini par une requête en lecture-écriture pour que les données de session soient effacées.

Source: ASP.NET l'État de Session "vue d'ensemble de 1519100920" , mon accent

3
répondu sisve 2011-05-09 04:48:20