當(dāng)一個aspx頁面請求處理包括大量的IO工作,而這些IO資源又非常有限的情況下,那這個頁面在對面大量請求的時候就有可能導(dǎo)致大量線程等待處理,從而使應(yīng)用程序線程開銷過多影響整體的處理效能.在這種情況我們更希望通過一個隊列的機制控制處理線程的開銷來實現(xiàn)更高效的處理效能.因此.net提供IHttpAsyncHandler來解決這些事情,但有個問題就是實現(xiàn)一個IHttpAsyncHandler意味著要自己要實現(xiàn)自己的處理過程,并不能對已經(jīng)實現(xiàn)功能的.aspx進行控制.但通過反編譯.net代碼來看可以實現(xiàn)一個IHttpAsyncHandler接管現(xiàn)有的.aspx頁面實現(xiàn)異步處理,又不需要修改現(xiàn)有頁面實現(xiàn)的代碼.下面詳細(xì)講述實現(xiàn)過
從.net的web配置文件來看asp.net默認(rèn)處理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就可以直接處理現(xiàn)有的aspx文件.
實現(xiàn)IHttpAsyncHandler
既然可以重寫PageHandlerFactory的GetHandler,而IhttpAsyncHandler又是繼承IHttpHandler;那事情就變得簡單多了可能通過構(gòu)建一個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;
}
}
可以實現(xiàn)一個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就可以實現(xiàn)對現(xiàn)有的aspx進行異步隊列處理.
隊列和線程控制
在處理的過程中并沒有使用線程池來完成具體的工作,如果每個直接調(diào)用線程池那同樣面臨的問題就是線池線耗出現(xiàn)大量線程調(diào)度問題影響性能.所以在上面實現(xiàn)IHttpAsyncHandler的BeginProcessRequest方法中是構(gòu)建一個IAsyncResult添加到隊列中.之于這個隊列的實現(xiàn)相對比較簡單:
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);
}
}
}
}
}
為了更好地控制線程,隊列的實現(xiàn)是采用多隊列多線程機制,就是根據(jù)你需要的并發(fā)情況來指定線程隊列數(shù)來處理,當(dāng)然這種設(shè)計是比較死板并不靈活,如果想設(shè)計靈活一點是根據(jù)當(dāng)前隊列的處理情況和資源情況來動態(tài)計算擴沖現(xiàn)有隊列線程數(shù).