在 Asp.net MVC 應用程序中,有時間需要執行一些異步操作。那么 Asp.net MVC 下的異步請求是怎么一個過程呢? 異步被調用時,發生以下過程:
1. Web服務器從線程池得到一個線程(工作線程),接着安排它來處理進來的請求,該工作線程啟動一個異步操作。
2. 工作線程被線程池收回,為另一個Web請求服務。
3. 當異步操作完成后,它會通知ASP.NET。
4. Web服務器從線程池獲取一個工作線程(這可能是一個不同的開始異步操作的線程)來處理剩余的請求,包括呈現與響應請求。
看下面的模式圖:

接着,我們來看Controller的代碼:
1: public class HomeController : AsyncController
2: {
3: public void IndexAsync()
4: {
5: AsyncManager.OutstandingOperations.Increment(2);
6:
7: Task.Factory.StartNew(() =>
8: {
9: // Perform some expensive operation
10: string uri = "http://www.cnblogs.com";
11:
12: WebClient client = new WebClient();
13: string reply = client.DownloadString(uri);
14:
15: AsyncManager.Parameters["data"] = reply;
16: AsyncManager.OutstandingOperations.Decrement();
17: });
18: Task.Factory.StartNew(() =>
19: {
20: // Perform another expensive operation
21: string uri = "http://www.cnblogs.com/wintersun/";
22:
23: WebClient client = new WebClient();
24: string reply = client.DownloadString(uri);
25:
26: AsyncManager.Parameters["moredata"] = reply;
27: AsyncManager.OutstandingOperations.Decrement();
28: });
29: }
30:
31: public ActionResult IndexCompleted(string data, string moredata)
32: {
33: Operations translations = new Operations { FirstOperation = data, SecondOperation = moredata };
34:
35: return View(translations);
36: }
37:
38: }
我們看到上面的代碼讓Controller繼承自AsyncController,那個叫IndexAsync的action對應是Index的View。中間的代碼使用Task Parallel library(TPL)來模擬下載網頁內容,最后在完成后又通過AsyncManager.Parameters字典傳值給IndexCompleted的Action, 有注意Key的名稱moredata與IndexCompleted Action的參數名moredata相同。AsyncManager下的Parameters字典用於轉遞一組參數值到最后異步調用的方法。 AsyncManager下有一個管理異步操作的計數器,應當務必確保執行異步操作后,執行Decrement方法,甚至異步操作失敗,當所有線程完成時這個計數器的值必須為0。 當異步調用我們讓View返回:
1: <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<AsyncProject.Models.Operations>" %>
2: <!DOCTYPE html>
3: <html>
4: <head runat="server">
5: <title>Translate Completed</title>
6: </head>
7: <body>
8: <div>
9: The controller has completed.
10: </div>
11: </body>
12: </html>
使用到一個簡單Model:
public class Operations
{
public string FirstOperation { get; set; }
public string SecondOperation { get; set; }
}
好了,那么什么時候用異步,什么用同步呢?
當這些條件滿足的情況下,可以考慮使用異步:
1. 密集地操作的網絡或I/O,而不是CPU密集運算的。
2. 測試結果表明阻塞操作是網站的性能瓶頸,為了讓IIS服務器可以處理更多的請求,在處理這些阻塞調用時使用異步Action方法。
3. 並行化比簡單代碼更重要。
4. 需要提供一種機制,允許用戶取消一個長期運行任務的請求。
實際開發,你需要測試是否異步操作可以提高性能。同時,在某些情況下可能話,增加IIS每個CPU配置最大並發請求處理和最大並發線程。
關於Asp.net 服務器線程配置看這篇文章:ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0
關於是否需要數據庫異步調用看這里: Should my database calls be Asynchronous
我們介紹到這兒,有興趣可以自己嘗試一下,后面有時間將介紹Asp.net MVC 4 與 .net framework 4.5 的異步操作。
作者:Petter Liu
出處:http://www.cnblogs.com/wintersun/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
該文章也同時發布在我的獨立博客中-Petter Liu Blog。