2010-12-15 91 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

相关问题