出于 ASP.NET Web 应用程序的日志记录目的,我将一些状态信息保存在静态类中。这些字段被标记为[ThreadStatic]
,因此每个线程都有自己的字段副本。日志记录方法是从 HttpApplication 事件方法调用的:
- Application_BeginRequest(请求开始,初始化状态)
- Application_AcquireRequestState( session 和用户已知)
- Application_EndRequest(请求结束,清理)
我现在可以观察到,在某些情况下,页面请求是在不同的线程中处理的。 BeginRequest 事件在线程 18 上运行,而以下事件在线程 4 上运行。当然,我的线程静态数据将不可用,并且会发生错误。
大多数情况下,这工作得很好,每个请求仅在单个线程中处理。但是,当我请求加载约 5 秒的页面并在 1-2 秒后单击另一个链接时,两个请求并行运行。第一个请求在 5 秒后在线程 24(它也在线程 24 上启动)上完成,而另一个请求在线程 18 上启动,但在第一个请求完成后,第二个请求继续在线程 4 上运行。
尝试使用 3 个重叠的长请求,这纯粹是困惑。我什至可以观察在同一线程上启动的两个请求,而它们随后在不同的线程上继续。请求和线程之间似乎没有任何关系。
请求怎么会改变线程呢?如果它决定转移到另一个线程,它就会丢失所有状态。我能找到的每个描述都表明这一切都发生在单个线程中。
IIS 7、Windows Server 2008 R2、x64 上的 ASP.NET 4.0。
替代方案:如果我不能依赖从开始到结束仅在单个线程中处理请求,那么存储少量每个请求数据的最佳位置是什么(目前一个整数和一个类),访问速度非常快?并且最好在不引用 System.Web 的情况下也能工作(我的代码也针对客户端配置文件)。我知道 HttpContext.Current.Items[key]
但它在远程处理程序集的深处查找,并且涉及一个字典,它看起来比线程静态字段慢很多。
最佳答案
ASP.NET 是 thread agile并且一个请求可以在多个线程上处理(但一次不能超过一个)。因此,您确实无法在 ASP.NET 中使用 ThreadStatics。但是,您可以安全地使用 HttpContext.Items 字典来存储需要限制为单个请求的内容。
要允许您的代码在 ASP.NET 应用程序的上下文之外工作,您可以创建一个交换 HttpContext/CallContext 的包装器,具体取决于代码所在的环境。Here is an example of such a wrapper .
关于asp.net - HttpApplication 事件改变线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24083360/