为什么Global.asax.cs中的Session_Start会导致性能问题?

时间:2010-12-15 15:41:25

标签: asp.net global-asax

当我在Global.asax.cs中创建一个空的Session_Start处理程序时,它会在向浏览器呈现页面时造成重大影响。

如何重现:

创建一个空的ASP.NET MVC 3 Web应用程序(我正在使用MVC 3 RC2)。 然后使用以下代码添加Home控制器:

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

接下来创建一个视图Home / Index.cshtml并将以下内容放在BODY部分中:

@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),那么它似乎没问题。所以,也许这不是一个重大问题,但它仍然很奇怪。

2 个答案:

答案 0 :(得分:12)

tl; dr :如果您在使用Webforms时遇到此问题,并且不需要对该特定页面中的会话状态进行写访问,请在EnableSessionState="ReadOnly"指令中添加@Page帮助


显然,仅Session_Start的存在迫使ASP.NET按顺序执行源自同一Session的所有请求。但是,如果您不需要对会话的写访问权,则可以逐页修复此问题(参见下文)。

我已经使用Webforms创建了自己的测试设置,它使用aspx页面来传递图像。 1

这是测试页面(纯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 s的随机混合,这意味着请求获得并行处理。

  • 运行2 ,将空Session_Start添加到global.asax(需要在浏览器中点击F5一次,不知道为什么会这样):{{ 1}}和Start替代,显示请求经常被处理。多次刷新浏览器会显示即使没有连接调试器,也会出现性能问题。

  • 运行3 ,如运行2,但将End添加到EnableSessionState="ReadOnly"的{​​{1}}指令:调试输出显示多个{{1在第一个@Page之前的s。我们再次并行,我们有良好的表现。


1 是的,我知道这应该用ashx处理程序来完成。这只是一个例子。

答案 1 :(得分:3)

无法告诉你调试器正在做什么(intellitrace?详细的日志记录?第一次机会异常?),但是你仍然掌握了处理并发请求的会话能力。

  

对每个会话的访问ASP.NET会话状态是独占的,这意味着如果两个不同的用户发出并发请求,则同时授予对每个单独会话的访问权限。 但是,如果对同一会话发出两个并发请求(通过使用相同的SessionID值),则第一个请求将获得对会话信息的独占访问权。第二个请求仅在第一个请求完成后执行。(如果由于第一个请求超过锁定超时而释放信息的独占锁定,则第二个会话也可以访问。)如果EnableSessionState值为@ Page指令设置为ReadOnly,对只读会话信息的请求不会导致会话数据的独占锁定。但是,会话数据的只读请求可能仍然需要等待会话数据的读写请求设置的锁定才能清除。

来源:ASP.NET Session State Overview,我的重点