在上一章 Asp.Net Core 輕鬆學-多線程之Task快速上手 文章中,介紹了使用Task的各類經常使用場景,可是感受有部份內容尚未完善,在這裏補充一下。html
在使用 Task 進行基於隊列的異步任務(TAP)的時候,對於剛入門的同窗來講,只是簡單的瞭解了使用 Task 能夠在後臺處理異步任務,可是對於阻塞調用可能還有有一些不太明白,異步任務默認是不阻塞的執行過程,當一個 Task 被建立出來的時候,並無被壓入隊列中,而是開始執行的時候,纔會進入隊列中;執行一個異步任務能夠設置等待git
[HttpGet] public async Task<string> Get() { string result = string.Empty; await Task.Run(() => { result = "Hello World!"; }); return result; }
上面的異步方法 Get() 內部執行了一個 Task,爲了保持方法在返回的時候可以給變量 result 設置值,這裏使用了 await 等待任務完成,在任務未完成前,即 result 未被設置值 Hello World! 前,該接口將一直阻塞,直到任務完成。github
[HttpGet("WaitTest")] public string WaitTest(int id) { string result = string.Empty; var waitTask = Task.Run(() => { result = "Hello World!"; }); waitTask.Wait(TimeSpan.FromSeconds(5)); return result; }
上面的代碼定義了一個 TAP ,waitTask 使用了 Wait() 方法進行等待並傳入一個時間,表示等待 5 秒中後退出阻塞過程,多線程
[HttpGet("WaitToken")] public string WaitToken(int id) { var result = string.Empty; CancellationTokenSource cts = new CancellationTokenSource(); var taskToken = Task.Run(() => { cts.CancelAfter(TimeSpan.FromSeconds(1)); Task.Delay(2000).Wait(); result = "Hello World!"; }); taskToken.Wait(cts.Token); return result; }
上面的任務 taskToken ,則使用了取消令牌,當令牌沒有收到取消通知的時候,該任務將一直等待, taskToken 任務內部指示取消令牌 1 秒後取消,同時,任務內部使用 Task.Delay 阻塞 2 秒,這很特別,這種設置使得 taskToken 任務將引起任務取消的異常而致使沒法給 result 變量進行值設置,若是你對取消令牌不太瞭解,建議閱讀我以前的文章 Asp.Net Core 輕鬆學-多線程之取消令牌app
在同步方法中,咱們能夠很是容易的建立一個 Task 任務,特別是 .Net Core 提供了 Task 這麼方便的使用方式的狀況下,在某些場景下,就會出現一些意想不到的問題,個人忠告是:在使用 TAP 的時候,儘量的使用可等待的任務,特別是須要注意不要在 TAP 中運行一些耗時較長的任務,好比批量處理數據、事務過程等等,若是真的是須要有這一類型的任務須要使用 Task 進行處理,那麼個人建議是,將這些任務縮小,而後儘快的結束,好比,你可使用消息隊列來執行批量處理數據,而 Task 的任務則縮小至把處理條件丟到消息隊列中,這樣的解耦纔是正確的選擇,長時間運行於後臺的 TAP,經常致使許多問題,好比消息冒泡、服務重啓,都有可能會中斷 TAP 線程,要知道,全部的 TAP 都是後臺線程,當主進程退出的時候,後臺線程也將被清理異步
在 TheadPool 內部,提供了一個排隊的方法,當線程池資源可用後,將會自動的執行該隊列,這樣作的好處顯而易見,就是你能夠經過定義一系列的任務,而後等待線程池去按順序處理它,這個排隊的過程本質上就是隊列async
[HttpGet("TaskQueue")] public bool TaskQueue() { var inQueues = ThreadPool.QueueUserWorkItem(ThreadProc); return inQueues; } private void ThreadProc(Object stateInfo) { Console.WriteLine("此任務來自線程池隊列執行"); }
上面的代碼中,在 TaskQueue() 內部使用 ThreadPool.QueueUserWorkItem() 將方法 ThreadProc(Object stateInfo) 壓入隊列中,並返回一個值:inQueues ,該值指示任務壓入隊列是否成功,在 .Net Core 中,ThreadPool.QueueUserWorkItem() 提供了 3 個方法重載,能夠按需使用;使用重載方法,甚至能夠在壓入任務的時候傳入參數調用,相似下面的代碼測試
[HttpGet("TaskQueue")] public bool TaskQueue() { var inQueues = ThreadPool.QueueUserWorkItem(ThreadProc); var inQueuesSecond = ThreadPool.QueueUserWorkItem(ThreadProc, "這是一條測試消息"); return inQueues; } private void ThreadProc(Object stateInfo) { Console.WriteLine(stateInfo); }
若是業務須要,該參數還可傳入實體對象hybrid-app
使用混合方法執行 TAP 的好處是,能夠隱藏業務實現細節,提供統一調用入口線程
[HttpGet("HyBrid")] public Task<string> HyBrid([FromQuery]string value) { return HyBridInternal(value); } private async Task<string> HyBridInternal(string value) { await Task.Run(() => { Console.WriteLine(value); }); return "Your Input:" + value; }
混合方法,不要被它的名頭唬住,你能夠把它當作一個方法重載,這樣作的好處是,當發生異常是,你能夠快速的定位到出現異常的方法,而不是任務
本文的內容只是上一篇文章的補充,因此這裏就不在放入執行結果,可是示例代碼仍是同樣的奉上
https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.TaskSecond