在 IHttpAsyncHandler 中使用 Task 或 async/await
自從我想添加執行緒開始編寫 ASP.NET 應用程序以來,有 3 種簡單的方法可以在我的 ASP.NET 應用程序中完成執行緒:
- 使用
System.Threading.ThreadPool.- 使用自定義委託並呼叫其
BeginInvoke方法。- 在類的幫助下使用自定義執行緒
System.Threading.Thread。前兩種方法提供了一種為您的應用程序啟動工作執行緒的快速方法。但不幸的是,它們會損害應用程序的整體性能,因為它們使用 ASP.NET 用來處理 HTTP 請求的同一池中的執行緒。
然後我想用一個新的 Task 或者 async/await 來寫
IHttpAsyncHandler. 你可以找到一個例子是 Drew Marsh 在這裡解釋的:https ://stackoverflow.com/a/6389323/261950我的猜測是,使用 Task 或 async/await 仍然會消耗 ASP.NET 執行緒池中的執行緒,並且出於明顯的原因我不想要。
您能否告訴我是否可以在後台執行緒上使用 Task (async/await),例如使用
System.Threading.Thread類而不是執行緒池?在此先感謝您的幫助。
托馬斯
這幾天一直在網上找資料。讓我總結一下我到目前為止的發現:
ASP.NET 執行緒池事實
- 正如 Andres 所說:當 async/await 不會消耗額外的 ThreadPool 執行緒時?僅在您使用 BCL 非同步方法的情況下。使用 IOCP 執行緒執行 IO 綁定操作。
- Andres**繼續… _ _ _
但據我所知,您無法選擇是否要使用 IOCP 執行緒,並且正確實現 threadPool 是不值得的。我懷疑有人做得更好,已經存在。
- ASP.NET 使用公共語言執行時 (CLR) 執行緒池中的執行緒來處理請求。只要執行緒池中有可用的執行緒,ASP.NET 就可以毫無問題地分派傳入的請求。
- 非同步
delegates使用 ThreadPool 中的執行緒。什麼時候應該開始考慮實現非同步執行?
- 當您的應用程序執行相對冗長的 I/O 操作(數據庫查詢、Web 服務呼叫和其他 I/O 操作)時
- 如果你想做 I/O 工作,那麼你應該使用 I/O 執行緒(I/O 完成埠),特別是你應該使用你正在使用的任何庫類支持的非同步回調。
Begin他們的名字以and開頭End。- 如果請求在計算上處理起來很便宜,那麼並行性可能是不必要的成本。
- 如果傳入的請求率很高,那麼增加更多的並行性可能不會帶來什麼好處,實際上可能會降低性能,因為傳入的工作率可能高到足以讓 CPU 保持忙碌。
我應該創建新執行緒嗎?
- 避免像避免瘟疫一樣創建新執行緒。
- 如果您實際上排隊了足夠多的工作項以防止 ASP.NET 處理進一步的請求,那麼您應該餓死執行緒池!如果您實際上同時執行數百個 CPU 密集型操作,那麼當機器已經超載時,讓另一個工作執行緒來服務 ASP.NET 請求會有什麼好處。
TPL 呢?
- TPL 可以適應在程序中使用可用資源。如果伺服器已經載入,TPL 可以使用最少一個工作人員並向前推進。如果伺服器大部分是免費的,它們可以增長到使用執行緒池可以騰出的盡可能多的工作人員。
- 任務使用執行緒池執行緒來執行。
參考
- <http://msdn.microsoft.com/en-us/magazine/cc163463.aspx>
- <http://blogs.msdn.com/b/pfxteam/archive/2010/02/08/9960003.aspx>
- <https://stackoverflow.com/a/2642789/261950>
這種情況是
Task,async和await真正閃耀的地方。這是相同的範例,經過重構以充分利用async(它還使用我的AsyncEx庫中的一些幫助程序類來清理映射程式碼):// First, a base class that takes care of the Task -> IAsyncResult mapping. // In .NET 4.5, you would use HttpTaskAsyncHandler instead. public abstract class HttpAsyncHandlerBase : IHttpAsyncHandler { public abstract Task ProcessRequestAsync(HttpContext context); IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { var task = ProcessRequestAsync(context); return Nito.AsyncEx.AsyncFactory.ToBegin(task, cb, extraData); } void EndProcessRequest(IAsyncResult result) { Nito.AsyncEx.AsyncFactory.ToEnd(result); } void ProcessRequest(HttpContext context) { EndProcessRequest(BeginProcessRequest(context, null, null)); } public virtual bool IsReusable { get { return true; } } } // Now, our (async) Task implementation public class MyAsyncHandler : HttpAsyncHandlerBase { public override async Task ProcessRequestAsync(HttpContext context) { using (var webClient = new WebClient()) { var data = await webClient.DownloadDataTaskAsync("http://my resource"); context.Response.ContentType = "text/xml"; context.Response.OutputStream.Write(data, 0, data.Length); } } }(如程式碼中所述,.NET 4.5 有一個
HttpTaskAsyncHandler類似於我們HttpAsyncHandlerBase上面的)。真正酷的是它在執行後台操作時
async不佔用任何執行緒:
- 一個 ASP.NET 請求執行緒啟動請求,並開始使用
WebClient.- 在下載過程中,
await實際從方法中返回async,離開請求執行緒。該請求執行緒返回到執行緒池 - 留下 0(零)個執行緒為該請求提供服務。- 當下載完成時,該
async方法在請求執行緒上恢復。該請求執行緒僅用於編寫實際響應。這是最佳的執行緒解決方案(因為需要一個請求執行緒來編寫響應)。
原始範例還以最佳方式使用執行緒 - 就執行緒而言,它與
async基於 - 的程式碼相同。但 IMO 的async程式碼更容易閱讀。如果您想了解更多關於的資訊,我的部落格上
async有一篇介紹文章。