說到這就不得不談.net的異步處理(Asynchronous),模型一般爲BeginXXX,EndXXX,BeginXXX返回一個IAsycResult對象,其中包含對當前異步操作的信息,而EndXXX用戶接受返回值,輸出參數。.net從ThreadPool中分配一個空閒線程給BeginXXX然後立即返回給ThreadPool,等到異步處理結束時,.net又從ThreadPool中分配一個空閒線程用於處理EndXXX方法。這樣就可能有足夠的線程用於處理其它的事情。見於篇幅問題這裏我們只談asp.net 2.0的異步處理模型,我們都知道在1.x的時候要很好的建立頁面的異步處理是比較麻煩的,可能微軟很早就認識到了這一點,所以在2.0的版本中引入的新的頁面處理模型,加入了方便的異步處理點(Asynchronous Point)在PreRender事件和PreRenderComplete事件之間,在這個異步點,頁面需要等待所有的異步處理都完成,所以可以在頁面呈現之前完成你需要的任何效果,極大簡化了建立異步頁面的方法。
首先你要在建立頁面的@page聲明中加入 Async="true",這是必須的。設置告訴asp.net要選用IHttpAsyncHandler來處理當前的頁面。接下來你需要做的一般是在Page_Load事件處理中使用異步處理過程,現在有兩種途徑:
第一種就是使用Page.AddOnPreRenderCompleteAsync方法來處理需要異步處理的Begin和End方法集.如下:
AddOnPreRenderCompleteAsync(new BeginEventHandler(MyBeginMethod),new EndEventHandler(myEndMethod)); |
通過添加上面的方法後,頁面執行通常的生命週期事件直到頁面的PreRender事件觸發.然後Asp.net調用先前在AddOnPreRenderCompleteAsync中的註冊的Begin處理程序。通常在Begin處理程序中處理的是一些異步的web服務,IO以及SQL的處理,這樣就可以極大的緩解.net線程池的壓力。例如:
<%@ Page Async="true" Language="C#" %> <asp:Content ID="Content" ContentPlaceHolderID="Main" Runat="server"> <asp:Label ID="Output" Runat="server"></asp:Label> </asp:Content> public partial class AsyncPage : System.Web.UI.Page { private WebRequest m_Request; void Page_Load (object sender, EventArgs e) { AddOnPreRenderCompleteAsync ( new BeginEventHandler(BeginAsyncOperation), new EndEventHandler (EndAsyncOperation) ); } IAsyncResult BeginAsyncOperation (object sender, EventArgs e, AsyncCallback cb, object state) { m_Request = WebRequest.Create("http://www.dofor.cn"); return m_Request.BeginGetResponse (cb, state); } void EndAsyncOperation (IAsyncResult ar) { string text; using (WebResponse response = m_Request.EndGetResponse(ar)) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { text = reader.ReadToEnd(); } } Regex regex = new Regex ("href//s*=//s*/"([^/"]*)/"", RegexOptions.IgnoreCase); MatchCollection matches = regex.Matches(text); StringBuilder builder = new StringBuilder(1024); foreach (Match match in matches) { builder.Append (match.Groups[1]); builder.Append("<br/>"); } Output.Text = builder.ToString (); } } |
第二中就是註冊異步任務(Register Asynchronous Task).RegisterAsyncTask比AddOnPreRenderCompleteAsync具有更大的靈活性和更多的優勢。它可以允許你聲明一個超時參數,同樣可以聲明在@Page中如:AsyncTimeout="5",以秒爲單位,但要注意的是這裏聲明不是每個異步處理過程的超時而是整個頁面的處理時間超時。同樣.net framework 2.0還爲註冊任務引入了新的MethodAsync,MethodAsync就是爲了方便處理多個異步過程的。例如:
<%@ Page Async="true" Language="C#" %> <asp:Content ID="Content" ContentPlaceHolderID="Main" Runat="server"> <asp:Label ID="Output" Runat="server"></asp:Label> </asp:Content> public partial class AsyncPageTask : System.Web.UI.Page { private WebRequest m_Request; protected void Page_Load(object sender, EventArgs e) { PageAsyncTask task = new PageAsyncTask( new BeginEventHandler(BeginAsyncOperation), new EndEventHandler(EndAsyncOperation), new EndEventHandler(TimeoutAsyncOperation), null ); RegisterAsyncTask(task); } IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback cb, object state) { m_Request= WebRequest.Create("http://www.dofor.cn"); return m_Request.BeginGetResponse(cb, state); } void EndAsyncOperation(IAsyncResult ar) { string text; using (WebResponse response = m_Request.EndGetResponse(ar)) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { text = reader.ReadToEnd(); } } Regex regex = new Regex("href//s*=//s*/"([^/"]*)/"", RegexOptions.IgnoreCase); MatchCollection matches = regex.Matches(text); StringBuilder builder = new StringBuilder(1024); foreach (Match match in matches) { builder.Append(match.Groups[1]); builder.Append("<br/>"); } Output.Text = builder.ToString(); } void TimeoutAsyncOperation(IAsyncResult ar) { Output.Text = "當前數據不可用"; } } |
總之合理的利用asp.net 2.0的異步處理,就可以極大的改善您大吞吐量高併發網站頁面的性能。