你可能看到的是.NET中常被称为线程敏捷性的问题。在主题标签下方的结果(即
System.Web.HttpApplication.BeginRequest()
),你看到的大多数时间并不一定是正在执行的代码,而是Web上下文等待线程从读写锁中释放回来的时间。
Application_BeginRequest()
的“暂停”在ASP.NET Web堆栈中非常普遍。通常情况下,在BeginRequest中看到长时间加载时,你正在处理ASP.NET线程敏捷性和/或线程锁 - 尤其是在处理IO和基于会话的操作时。这并不是什么坏事,这只是.NET确保你的线程保持并发的方式。
时间差通常发生在BeginRequest和PreRequestHandlerExecute之间。如果应用程序将多个内容写入会话,则ASP.NET将对
HttpContext.Current.Session
发出读写锁。
一个好的方法是检查线程ID以确定是否面临线程敏捷性的问题 - 对于给定的请求,ID将是不同的。
例如,在调试时,你可以添加以下内容到你的
Global.asax.cs
:
protected void Application_BeginRequest(Object sender, EventArgs e) {
Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString());
}
打开调试输出窗口(从Visual Studio: View >> Output,然后从“show output from”下拉菜单中选择“Debug”)。
在调试时,进入你看到长时间等待的页面。然后查看输出日志--如果你看到多个id,则可能会遇到这个问题。
这就是为什么有时候你会看到延迟,而有时候你不会看到延迟,应用程序代码可能会以略微不同的方式使用session,或者从页面到页面的session或IO操作可能会更高或更低。
如果是这种情况,根据站点或每个给定页面上如何使用session,可以采取一些措施来帮助加快速度。
对于不修改session的页面:
<% @Page EnableSessionState="ReadOnly" %>
对于不使用会话状态的页面:
<% @Page EnableSessionState="False" %>
如果应用程序不使用session(web.config):
<configuration>
<system.web>
<sessionState mode="Off" />
</system.web>
</configuration>
让我们以以下示例为例:
用户加载一个页面,然后在第一个请求完成加载之前决定进入另一个页面,ASP.NET将强制进行会话锁定,导致新页面请求的加载等待直到第一个页面请求完成。使用ASP.NET MVC时,每个操作都会锁定用户会话以进行同步,从而导致相同的问题。
所有花费在解锁的时间都将通过New Relic报告,更不用说那些用户放弃会话并且线程回来寻找不再存在的用户的情况了。
顺便提一下,UpdatePanel控件会导致相同的行为 - http://msdn.microsoft.com/en-us/magazine/cc163413.aspx
可以采取的措施:
这个锁定问题是微软拥有SessionStateUtility类的原因之一 - http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
因此,如果您遇到此问题,可以覆盖默认行为,就像在此Redis实现中所看到的那样:https://github.com/angieslist/AL-Redis
.net基础网站使用的默认状态提供程序有许多选项。但是通常知道,这个事务时间表示线程被锁定并等待请求完成。