深入理解ASP.NET MVC(9)

來源:互聯網
上載者:User

系列目錄

非同步處理請求的意義

大伙兒都知道,ASP.NET通過線程池處理請求,對於每個請求從線程池中請求一個可用的線程來處理請求,當請求處理完畢之後,線程資源將被歸還到線程池。然而,線程池中的線程是互斥資源,當網站在同一時刻的請求量達到一定數量的話,必然會導致這種資源不夠耗盡,新來的請求只能等待有新的線程歸還才能被處理。當然這不是最糟糕的,通常每個請求只需要很短的時間就可以了,新的請求不會等待太長的時間,但是,如果處理請求需要花費較長的時間呢?比如一次耗時的資料庫查詢、一次外部web service請求這類的IO操作。注意這裡特指的IO操作,指的是不會佔用ASP.NET線程池線程的,甚至不佔用本機CPU資源的操作。正因為如此,非同步處理請求在這種情況下尤其適用。當非同步處理請求時,佔用的線程會在耗時的IO操作開始前,將線程歸還給線程池,直到IO操作完成後,再從線程池中請求一個線程,並恢複當時的HttpContext,處理IO操作的結果。這樣就不會佔用寶貴的線程資源了。

 

MVC中的非同步Controller機制

MVC支援非同步地處理請求。可以通過下面的三種方式:

  1. 實現一個自訂的RouteHandler,並為GetHttpHandler方法返回一個實現IHttpAsynHandler的對象。
  2. 建立一個自訂的基類Controller,並實現IAsyncController,IAsyncController是IController的非同步版本。
  3. MVC內建了一個AsyncController,它實現了上述的IAsyncController,通過簡單的繼承AsyncController,即可實現非同步。

下面僅對第三種方法作簡單介紹。假設某個Action需要調用一個web service,並處理結果後返回:

public ContentResult GetPhotoByTag(string tag){...using (var response = WebRequest.Create(url).GetResponse()){// Parse the response as XMLvar xmlDoc = XDocument.Load(XmlReader.Create(response.GetResponseStream()));...}...}

顯然,如果這個web request消耗2s,那麼這個請求將hold這個線程至少2s。這種同步的處理方式顯然不合理,想要非同步處理,只需按如下步驟進行:

1、替換基類Controller為AsyncController

2、建立兩個配對的Action:ActionNameAsync和ActionNameCompletedActionNameAsync方法必須返回void,在內部啟動一個耗時的IO操作前,需要使用AsyncManager.OutstandingOperations.Increment()向MVC架構“註冊啟動”,在IO方法返回後,可以在AsyncManager.Parameters字典中儲存希望傳給ActionNameCompleted方法的參數。最後調用AsyncManager.OutstandingOperations.Decrement()通知MVC架構操作完成,此時,MVC架構會自動調用ActionNameCompleted。ActionNameCompleted需要向通常的Action一樣,返回一個ActionResult。因此上面的代碼需要改寫成如下這樣:

public void GetPhotoByTagAsync(string tag){//向MVC中註冊啟動AsyncManager.OutstandingOperations.Increment();...WebRequest request = WebRequest.Create(url);//啟動一個非同步web requestrequest.BeginGetResponse(asyncResult =>{using (WebResponse response = request.EndGetResponse(asyncResult)){var xml = XDocument.Load(XmlReader.Create(response.GetResponseStream()));...//將結果photoUrls,儲存在AsyncManager.Parameters中AsyncManager.Parameters["photoUrls"] = photoUrls;//通知MVC架構操作完成 ,準備調用CompletedAsyncManager.OutstandingOperations.Decrement();}}, null);}//像通常的Action一樣,這裡的參數photoUrls將在AsyncManager.Parameters中匹配public ContentResult GetPhotoByTagCompleted(IEnumerable<string> photoUrls){return Content(string.Format("<img src='{0}'/>", photoUrls.First()));}

當然,可以設定非同步作業的逾時時間:

[AsyncTimeout(10000)] // 10000 milliseconds equals 10 secondspublic void GetPhotoByTagAsync(string tag) { ... }

上面的代碼如果逾時了,將拋出TimeoutException異常,我們可以用希望的方式處理它。

當使用類似BeginGetResponse這類的非同步方法呼叫,並提供回呼函數參數時,你無法控制回呼函數調用在哪個線程上。大多數情況下,甚至不在ASP.NET的背景工作執行緒上。所以回呼函數無法關聯原始的HttpContext對象。

幸好,AsyncManager提供了一個Sync()方法,它會將一個委託在ASP.NET的背景工作執行緒上啟動,並關聯原始的HttpContext對象。而且它保證安全執行緒:

BeginAsyncOperation(asyncResult => {var result = EndAsyncOperation(asyncResult);// Can't always access System.Web.HttpContext.Current from here...Action doSomethingWithHttpContext = () => {// ... but can always access it from this delegate};if (asyncResult.CompletedSynchronously) // Already on an ASP.NET threaddoSomethingWithHttpContext();else // Must switch to an ASP.NET threadAsyncManager.Sync(doSomethingWithHttpContext);AsyncManager.OutstandingOperations.Decrement();}, null);

 

以上內容只是書中的內容摘錄。對非同步處理請求,我也沒有深入研究,等以後用到了再回過來研究吧。

 

ps:最近比較忙,沒有什麼時間關注在MVC上,見諒。

勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2011/01/07/details-asp-net-mvc-09.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.