聊聊多線程那一些事兒(task)之 三 異步取消和異步方法

   hello,咋們又見面啦,經過前面兩篇文章的介紹,對task的建立、運行、阻塞、同步、延續操做等都有了很好的認識和使用,結合實際的場景介紹,這樣一來在實際的工做中也可以解決很大一部分的關於多線程的業務,可是隻有這一些是遠遠不夠的,好比,好比,若是這麼一個場景,當開啓tsak異步任務後,有某個條件觸發,須要終止tsak的執行又該如何實現呢?這一些問題正是咱們今天須要交流分享的部分,帶着這一些問題,我們共同進入到今天的主題,謝謝!html

    在進入主題前,若是你沒有閱讀前面的兩篇文章,歡迎您點擊下面地址先閱讀一下,這樣可以更加連貫的掌握瞭解今天的內容,謝謝!c#

  第一篇:聊聊多線程哪一些事兒(task)之 一建立運行與阻塞多線程

  第二篇:聊聊多線程哪一些事兒(task)之 二 延續操做異步

  第三篇:聊聊多線程哪一些事兒(task)之 三 異步取消和異步方法async

 

Task之任務取消:CancellationTokenSource函數

 

    關於線程取消,我相信你們在實際工做中都會遇到這樣的問題,不管是採用哪種方式實現異步線程,都會有相應的機制來取消線程操做。本次將同時對Thread的線程取消實現,Tsak的線程取消實現同時經過實例說明。測試

    在個人工做經驗中,須要取消異步線程做業的實際使用場景每每是一些異步做業程序,也就是一些週期性的,循環業務操做。好比周期性的數據同步、數據更新等等操做。好比:電商系統常見的一個場景,訂單超時取消等等。spa

    爲了與前兩篇的實例保持一致性,我如今仍是以酒店平臺的數據同步業務爲例:.net

    需求:每週三凌晨3點鐘,經過攜程提供的酒店分頁查詢接口,全量同步一次最新的酒店數據。而且可以經過人爲的干預來終止數據同步操做。線程

    下面我將分別經過Thread和task兩種方式來實現

    其1、Thread時代之任務取消

    哈哈,實話實話說,在幾年前的項目中,我也是採用Thread來實現異步線程的,也會遇到線程的取消的業務場景。我當時的實現方式是,定義一個全局變量,isStopThread(是否終止線程),去過須要取消任務,只須要控制isStopThread的值便可,每一次執行具體的業務時,首先判斷一下isStopThread,只有非終止狀態才執行具體的業務邏輯。 /// <summary> /// 攜程 酒店數據同步做業(Thread) /// </summary>

 private static void CtripHoteDataSynchrByThread() { // CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); // 第一步經過thread開啓一個線程 Thread thread = new Thread(() => { // 獲取數據的次數 int getDataIndex = 1; isStopCtripHoteDataSynchr = false; // 經過調用攜程的分頁服務,獲取其有效的酒店數據 // 在獲取數據前,首先判斷一下是否終止獲取 
// while (!cancellationTokenSource.IsCancellationRequested)
 while (!isStopCtripHoteDataSynchr )
{ // 如今假設模擬,獲取攜程的全部有效的酒店數據經過 3 次就獲取完畢 Console.WriteLine($"開始獲取攜程第 {getDataIndex} 頁酒店數據....\n"); Thread.Sleep(3000); Console.WriteLine($"攜程第 {getDataIndex} 頁酒店數據獲取完畢\n"); getDataIndex++; // 模擬獲取完第三頁數據,表明數據獲取完畢,直接終止掉 if (getDataIndex == 4) { Console.WriteLine($"同步完畢攜程的全部酒店數據\n"); break; } } if (isStopCtripHoteDataSynchr) { Console.WriteLine($"取消同步攜程酒店數據\n"); } }); thread.Start(); Console.WriteLine("攜程酒店數據同步中.....\n"); // 模擬實際數據同步中的取消操做 Console.WriteLine("若是須要取消數據同步,那麼請輸入任意字符便可取消操做\n"); Console.ReadLine(); // cancellationTokenSource.Cancel(); isStopCtripHoteDataSynchr = true; Console.WriteLine($"發起取消同步攜程酒店數據請求\n"); }
 

執行結果:

    經過測試結果咱們能夠看到,在獲取第2頁數據時,此時發起了一個取消線程命令,當第二頁數據獲取完畢後,線程就裏面終止了,從而到達了線程取消的目的。

    其2、Task時代之任務取消

    隨着Task的推出,微軟也推出了一個專門服務於線程取消的幫助類(CancellationTokenSource),經過該類可以很好的幫助咱們取消一個線程,話很少說,咱們先經過CancellationTokenSource類實現上面示例的功能。

/// <summary>
 /// 攜程 酒店數據同步做業(Task)
 /// </summary>
 private static void CtripHoteDataSynchrByTask() { // 定義任務取消機制 CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); // 第一步經過thread開啓一個線程 Task thread = new Task(() => { // 獲取數據的次數 int getDataIndex = 1; // 經過調用攜程的分頁服務,獲取其有效的酒店數據 // 在獲取數據前,首先判斷一下是否終止獲取 while (!cancellationTokenSource.IsCancellationRequested) { // 如今假設模擬,獲取攜程的全部有效的酒店數據經過 3 次就獲取完畢 Console.WriteLine($"開始獲取攜程第 {getDataIndex} 頁酒店數據....\n"); Console.WriteLine($"攜程第 {getDataIndex} 頁酒店數據獲取完畢\n"); getDataIndex++; // 模擬獲取完第三頁數據,表明數據獲取完畢,直接終止掉 if (getDataIndex == 4) { Console.WriteLine($"同步完畢攜程的全部酒店數據\n"); break; } } if (cancellationTokenSource.IsCancellationRequested) { Console.WriteLine($"取消同步攜程酒店數據\n"); } }); thread.Start(); Console.WriteLine("攜程酒店數據同步中.....\n"); // 模擬實際數據同步中的取消操做 Console.WriteLine("若是須要取消數據同步,那麼請輸入任意字符便可取消操做\n"); Console.ReadLine(); // 直接取消線程  cancellationTokenSource.Cancel(); // 在指定時間後取消線程 // cancellationTokenSource.CancelAfter(1000);  Console.WriteLine($"發起取消同步攜程酒店數據請求\n"); }
 

測試結果:

 

    經過測試結果,兩種實現方式的結果徹底一致

    固然,CancellationTokenSource 還提供了CancelAfter(多久後取消)方法,來實現多久後取消線程。

    說到這兒,不知道你們有沒有發現一個問題CancellationTokenSource 其實現是否是與Task和Thread沒有多少關係,在第一個實例中經過Thread實現的線程取消,一樣能夠結合CancellationTokenSource 來實現。因此說,在開始我說CancellationTokenSource 是微軟提供的一個線程取消的一個幫助類就是這個緣由。其實我能夠打開CancellationTokenSource 的實現源碼,其實咱們就會一目瞭然,其取消線程的核心邏輯和咱們上面的說Thread取消的原理很相似,都是控制一個變量的值來實現,只是CancellationTokenSource 對其全部操做進行了一個封裝。其中的CancelAfter裏面是開啓了一個定義器,定時器的最終實現仍是和Canel同樣。若是想看CancellationTokenSource的源碼,你們能夠查看下面地址:https://www.cnblogs.com/majiang/p/7920102.html

最後須要說明的是Task與CancellationTokenSource都是.net Framework4.0+、.NET Core、.NET Standard。

 

異步方法之:(async/await)

 

    c#5.0微軟推出了一個新的特性那就是異步方法,其關鍵詞爲async。有了async咱們要實現一個異步方法就簡單的多啦,你會發現和實現一個同步方法很類似,只須要對方法加以async修飾便可。固然若是隻是簡單的修飾調用,那麼也會是同步調用,爲了達到真正的異步調用,每每是須要另一個關鍵詞await來配合使用。

    先簡單介紹一下async異步函數:

    async的三種返回類型:

    Tsak:其主要適用場景是,主程序只關心異步方法執行狀態,不須要和主線程有任何執行結果數據交互。

    Task<T>:其主要適用場景是,主程序不只僅關心異步方法執行狀態,而且還但願執行後返回一個數據類型爲T的結果

    void: 主程序既不關係異步方法執行狀態,也不關心其執行結果,只是主程序調用一次異步方法,對於除事件處理程序之外的代碼,一般不鼓勵使用 async void 方法,由於調用方不能

    在介紹一下await關鍵詞:

    await其顧名思義就是等待的意思,其運行原理就是:調用方執行到await時就會當即返回,可是異步方法等待異步執行結果。因此await只能存在於async修飾的異步方法體中,await不阻塞主線程,只是阻塞當前異步方法繼續往下執行,這樣就可以達到真正異步的目的。

下面以一個簡單的例子來講明一下每一種狀況的使用:

static void Main(string[] args) { Console.WriteLine("主線程開始\n"); Console.WriteLine("主線程調用同步方法:SynTest\n"); SynTest(); Console.WriteLine("主線程調用異步方法:AsyncTestNoAwait\n"); AsyncTestNoAwait(); Console.WriteLine("主線程調用異步方法:AsyncTestHasAwait\n"); AsyncTestHasAwait(); Console.WriteLine("主線程結束\n"); Console.ReadKey(); } /// <summary> /// 同步方法測試 /// </summary> public static void SynTest() { Console.WriteLine("同步方法SynTest開始運行\n"); Thread.Sleep(5000); Console.WriteLine("同步方法SynTest運行結束\n"); } /// <summary> /// 異步方法測試(不帶有 await關鍵詞) /// </summary> public static async void AsyncTestNoAwait() { Console.WriteLine("異步方法AsyncTestNoAwait開始運行\n"); Thread.Sleep(5000); Console.WriteLine("異步方法AsyncTestNoAwait運行結束\n"); } /// <summary> /// 異步方法測試(帶有 await關鍵詞) /// </summary> public static async void AsyncTestHasAwait() { Console.WriteLine("異步方法AsyncTestHasAwait開始運行\n"); await Task.Delay(5000); Console.WriteLine("異步方法AsyncTestHasAwait運行結束\n"); }

運行結果:

從運行結果咱們能夠很好的得出:

    一、異步方法async若是沒有await關鍵詞,其執行原理仍是同步調用

    二、await關鍵詞只能存在雲async修飾的方法體中

    三、異步方法async在調用時,只有遇到await關鍵詞後的程序塊纔是異步執行,其await關鍵詞前的代碼塊仍是同步執行

    好了,管理async先介紹到這兒,因爲時間和文章篇幅緣由,就不在詳細介紹,裏面還有不少內容須要注意,後續在根據實際作一個async/await的專題文章。

總結:

    到目前爲止,有關Task的3篇文章都到此結束,下面在回顧總結一下Task的相關功能點吧!

    一、Task的建立運行能夠有三種方式:new Task/Task.Factory/Task.Run

    二、Task的返回參數定義Task<返回類型>

        獲取返回值:Task.Result->要阻塞主流程

    三、Task線程的同步實現不只僅能夠經過RunSynchronously來實現同步運行,固然還能夠經過Task.Result/Task.Wait等方式來變向實現

    四、Task的wait/waitAll/waitAny實現阻塞等待執行結果

    五、Task的WhenAny、WhenAll、ContinueWith實現延續操做

    六、CancellationTokenSource實現異步任務取消

    七、異步方法之:(async/await)實現同步和異步調用等

 

猜您喜歡: 

 第一篇:聊聊多線程哪一些事兒(task)之 一建立運行與阻塞

 第二篇:聊聊多線程哪一些事兒(task)之 二 延續操做

END
爲了更高的交流,歡迎你們關注個人公衆號,掃描下面二維碼便可關注,謝謝:

isStopCtripHoteDataSynchr

原文出處:https://www.cnblogs.com/xiaoXuZhi/p/XYH_tsak_WhenAny1.html

相關文章
相關標籤/搜索