当一个aspx页面请求处理包括大量的IO工作,而这些IO资源又非常有限的情况下,那这个页面在对面大量请求的时候就有可能导致大量线程等待处理,从而使应用程序线程开销过多影响整体的处理效能.在这种情况我们更希望通过一个队列的机制控制处理线程的开销来实现更高效的处理效能.因此.net提供IHttpAsyncHandler来解决这些事情,但有个问题就是实现一个IHttpAsyncHandler意味着要自己要实现自己的处理过程,并不能对已经实现功能的.aspx进行控制.但通过反编译.net代码来看可以实现一个IHttpAsyncHandler接管现有的.aspx页面实现异步处理,又不需要修改现有页面实现的代码.下面详细讲述实现过
从.net的web配置文件来看asp.net默认处理aspx的并不是IHttpHandler而是System.Web.UI.PageHandlerFactory,反编译代码看下
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true), PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
public class PageHandlerFactory : IHttpHandlerFactory2, IHttpHandlerFactory
{
private bool _isInheritedInstance;
protected internal PageHandlerFactory()
{
this._isInheritedInstance = (base.GetType() != typeof(PageHandlerFactory));
}
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
{
return this.GetHandlerHelper(context, requestType, VirtualPath.CreateNonRelative(virtualPath), path);
}
IHttpHandler IHttpHandlerFactory2.GetHandler(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath)
{
if (this._isInheritedInstance)
{
return this.GetHandler(context, requestType, virtualPath.VirtualPathString, physicalPath);
}
return this.GetHandlerHelper(context, requestType, virtualPath, physicalPath);
}
public virtual void ReleaseHandler(IHttpHandler handler)
{
}
private IHttpHandler GetHandlerHelper(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath)
{
Page page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page), context, true) as Page;
if (page == null)
{
return null;
}
page.TemplateControlVirtualPath = virtualPath;
return page;
}
}
从反编译的代码来看,看到的希望.首先PageHandlerFactory是可以继承的,而GetHandler又是可重写的,有了这两个条件完全可以满足我们的需要.通过承继PageHandlerFactory就可以直接处理现有的aspx文件.
实现IHttpAsyncHandler
既然可以重写PageHandlerFactory的GetHandler,而IhttpAsyncHandler又是继承IHttpHandler;那事情就变得简单多了可能通过构建一个IhttpAsyncHandler直接返回.
public class CustomPageFactory : System.Web.UI.PageHandlerFactory{
static CustomPageFactory()
{
G_TaskQueue = new TaskQueue(20);
}
public static TaskQueue G_TaskQueue;
public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
{
AspxAsyncHandler handler = new AspxAsyncHandler(base.GetHandler(context, requestType, virtualPath, path));
return handler;
}
}
可以实现一个IHttpAsyncHandler把PageHandlerFactory返回的IHttpHandler重新包装一下
public class AspxAsyncHandler : IHttpAsyncHandler{
public AspxAsyncHandler(IHttpHandler handler)
{
mHandler = handler;
}
private IHttpHandler mHandler;
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
AspxAsyncResult result = new AspxAsyncResult(context, mHandler, cb);
CustomPageFactory.G_TaskQueue.Add(result);
return result;
}
public void EndProcessRequest(IAsyncResult result)
{
}
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
}
这样一个异步处理的httphandler就包装完了.我们只需要通过配置httphandler就可以实现对现有的aspx进行异步队列处理.
队列和线程控制
在处理的过程中并没有使用线程池来完成具体的工作,如果每个直接调用线程池那同样面临的问题就是线池线耗出现大量线程调度问题影响性能.所以在上面实现IHttpAsyncHandler的BeginProcessRequest方法中是构建一个IAsyncResult添加到队列中.之于这个队列的实现相对比较简单:
public class TaskQueue{
public TaskQueue(int group)
{
mDispatchs = new List
for (int i = 0; i < group; i++)
{
mDispatchs.Add(new Dispatch());
}
}
private IList
private long mIndex = 0;
private int GetIndex()
{
return (int)System.Threading.Interlocked.Increment(ref mIndex) % mDispatchs.Count;
}
public void Add(AspxAsyncResult aspAsync)
{
if (aspAsync != null)
{
mDispatchs[GetIndex()].Push(aspAsync);
}
}
class Dispatch
{
public Dispatch()
{
System.Threading.ThreadPool.QueueUserWorkItem(OnRun);
}
private Queue
public void Push(AspxAsyncResult aspAR)
{
lock (this)
{
mQueue.Enqueue(aspAR);
}
}
private AspxAsyncResult Pop()
{
lock (this)
{
if (mQueue.Count > 0)
return mQueue.Dequeue();
return null;
}
}
private void OnRun(object state)
{
while (true)
{
AspxAsyncResult asyncResult = Pop();
if (asyncResult != null)
{
asyncResult.Execute();
}
else
{
System.Threading.Thread.Sleep(10);
}
}
}
}
}
为了更好地控制线程,队列的实现是采用多队列多线程机制,就是根据你需要的并发情况来指定线程队列数来处理,当然这种设计是比较死板并不灵活,如果想设计灵活一点是根据当前队列的处理情况和资源情况来动态计算扩冲现有队列线程数.
本文导航
- 第1页: 首页
- 第2页: IAsyncResult实现
- 第3页: 测试效果和总结