在ASP.net 中,可以编写一个Class 继承IHttpHandler,其中有个IsReusable属性,表示是否可以重用。
我的疑问是:并发时,HttpHandlers可以重用吗?
1 调用原理
HttpHandler的调用原理是HttpApplication的ResumeSteps函数首先算出本请求应该用哪个IHttpHandler实例来执行请求,然后调用IHttpHandler的ProcessRequest方法执行请求。
反射看下源代码:
MapHandlerExecutionStep的Execute函数:
ResumeSteps函数的最后还有一句RecycleHandlers()调用,用来决定下次是否可重用这个IHttpHandler的实例:
根据IsReusable属性的值,决定是否销毁(没销毁,则下次直接使用,销毁了,自然不能重用了)
2 并发多个请求是否可以重用?
ASP.net执行请求的先是HttpApplication,然后由HttpApplication调用IHttpHandler执行ProcessRequest方法。
如果并发多个请求,则会创建多个HttpApplication的实例,这样新的HttpApplication的实例上,并没有Handler的实例缓存,所以会创建新的Handler的实例。
当然,这个2个请求结束后,HttpApplication的实例会被回收重用,下次请求进来,将使用已初始化好的Handler的实例。
3 调试证明:
- 准备一个Handler,传入的参数不同,执行不同的动作:
public class MyCallBack : IHttpHandler { public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { string name = context.Request.QueryString["Method"]; if (name == "Default") { Default(); } else if (name == "Test") { Test(); } else { } } public void Default() { Thread.Sleep(10000); HttpContext.Current.Response.Write("Default"); } public void Test() { HttpContext.Current.Response.Write("Test"); } }
2) 配置到Web.Config
<httpHandlers> <add verb="GET" path="MyCallBack.axd" type="MyCallBack"/> </httpHandlers>
3) 启动调试:
第一次请求,实例为:6757235
第二次请求,实例还是:6757235,证明实例是被重用的
第三次请求,实例还是:6757235,继续执行,让它卡住。
同时再发一次请求,结果能顺利命中Test
但是实例变了,原因是这个实例是另外一个HttpApplication 实例创建的。
4结论:
IHttpHandler的实例重用是在HttpApplication的基础上,即便重用,也不能保证整个Web应用程序中只有1个HttpHandler的实例。
如果某个方法执行很久,它不会拖累别的请求,原因是别的请求是在另外一个HttpApplication实例上工作的,当前执行很久的请求并不在同一个实例上。