ASP.NET MVC 非同步控制器 Asynchronous Controllers

過去 ASP.NET MVC 4 前為了撰寫非同步控制器 (AsyncController)
Controller 都必須繼承 AsyncController

但時代在變微軟在進化 ASP.NET MVC 4 之後,AsyncController 就被微軟閹割
未來要寫非同步控制器(Asynchronous Controllers)就更簡單
async/await 搭配 Task 物件的組合就可以達成

IIS TreadPool 不是就類似非同步處理了?

IIS 本身就有一個 TreadPool 來處理用戶端 Request Queue

  • 應用程式集區 > 你的應用程式AppPool > 進階設定 > 佇列長度
  • 佇列長度預設: 1,000 (.NET 4.5 預設最大值為5,000)
  • 佇列長度1,000實際大約只能處理 650 個併發用戶端,之後的請求皆回應 “HTTP 503 服務無法使用”

盲目的加大佇列長度,有可能會導致導致大量的記憶體耗用量和伺服器硬體的使用率不佳
每一條新的執行緒就要配置約1MB堆疊記憶體空間至TreadPool,如果佇列長度為5,000,大約消耗5GB的記憶體空間,可能會造成IIS 執行緒耗盡(TreadPool)

使用非同步控制器

使用非同步控制器(Asynchronous Controllers)目的為解決以上的問題
讓 Controller 接收到用戶端 Request 後,暫時把 Thread 歸還給 IIS
這樣就不會佔用 IIS 的 ThreadPool,保持通訊暢通
等到 Controller 執行完畢再去跟 IIS ThreadPool 請求另一條 Thread 來回應執行結果給用戶端

但也不是所有的 Controller 都要用非同步方式處理
應該要觀察你的 Controller 實作內容

使用同步方法的情境

  • 程式處理邏輯很單純
  • 程式執行時間很短暫
  • 程式運算主要都是 CPU 運算,而非需要耗用大量磁碟I/O或網路傳輸
  • public ActionResult Index()
    {
        ViewBag.SyncOrAsync = "Synchronous";
        var userService = new UserService();
        return View("User", userService.GetUser());
    }

使用非同步方法的情境

  • 程式運算需要耗用大量磁碟I/O或網路傳輸,而非 CPU運算
  • 可讓用戶端取消長期執行要求的需求
  • 當切換執行緒的好處高於內容切換的成本時
  • public async Task<ActionResult> Index()
    {
        ViewBag.SyncOrAsync = "Asynchronous";
        var userService = new UserService();
        return View("User", await userService.GetUserAsync());
    }

Controller 加上 async關鍵字,就為宣告該Action為非同步
方法中有一個 Await關鍵字為等待 GetUserAsync() 處理完才做回傳 Task<ActionResult>

適當的應用非同步可以讓系統整體運作更有效率,用戶端用起來也會更順暢

 

參考資料

https://docs.microsoft.com/zh-tw/aspnet/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4
https://blog.miniasp.com/post/2010/06/05/ASPNET-MVC-Developer-Note-Part-18-AsyncController
http://vito-note.blogspot.com/2013/03/asynchronous-controller.html
https://www.gushiciku.cn/pl/peqb/zh-tw
https://www.huanlintalk.com/2013/01/aspnet-application-and-asynchronous.html
訂閱
通知
guest
0 留言
預約回饋
查看所有留言