日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【转】1.9 Asp.Net Core 轻松学-多线程之取消令牌(

發布時間:2023/12/10 asp.net 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】1.9 Asp.Net Core 轻松学-多线程之取消令牌( 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 前言
  • 1. 多線程請求合并數據源
  • 2. 對長時間阻塞調用的異步取消令牌應用
  • 3. CancellationToken 的鏈式反應
  • 4. CancellationToken 令牌取消的三種方式
  • 結束語
  • 示例代碼下載

?

前言

????取消令牌(CancellationToken) 是 .Net Core 中的一項重要功能,正確并合理的使用 CancellationToken 可以讓業務達到簡化代碼、提升服務性能的效果;當在業務開發中,需要對一些特定的應用場景進行深度干預的時候,CancellationToken 將發揮非常重要的作用。

1. 多線程請求合并數據源

在一個很常見的業務場景中,比如當請求一個文章詳細信息的時候,需要同時加載部分點贊用戶和評論內容,這里一共有 3 個任務,如果按照常規的先請求文章信息,然后再執行請求點贊和評論,那么我們需要逐一的按順序去數據庫中執行 3 次查詢;但是利用 CancellationToken ,我們可以對這 3 個請求同時執行,然后在所有數據源都請求完成的時候,將這些數據進行合并,然后輸出到客戶端

1.1 合并請求文章信息

public static void Test(){Random rand = new Random();CancellationTokenSource cts = new CancellationTokenSource();List<Task<Article>> tasks = new List<Task<Article>>();TaskFactory factory = new TaskFactory(cts.Token);foreach (var t in new string[] { "Article", "Post", "Love" }){Console.WriteLine("開始請求");tasks.Add(factory.StartNew(() =>{var article = new Article { Type = t };if (t == "Article"){article.Data.Add("文章已加載");}else{for (int i = 1; i < 5; i++){Thread.Sleep(rand.Next(1000, 2000));Console.WriteLine("load:{0}", t);article.Data.Add($"{t}_{i}");}}return article;}, cts.Token));}Console.WriteLine("開始合并結果");foreach (var task in tasks){Console.WriteLine();var result = task.Result;foreach (var d in result.Data){Console.WriteLine("{0}:{1}", result.Type, d);}task.Dispose();}cts.Cancel();cts.Dispose();Console.WriteLine("\nIsCancellationRequested:{0}", cts.IsCancellationRequested);}

上面的代碼定義了一個 Test() 方法,在方法內部,首先定義了一個 CancellationTokenSource 對象,該退出令牌源內部創建了一個取消令牌屬性 Token ;接下來,使用 TaskFacory 任務工廠創建了 3 個并行任務,并把這個任務存入 List<Task> 列表對象中,在任務開始后,馬上迭代 tasks 列表,通過同步獲取每個任務的執行 Result 結果,在取消令牌沒有收到取消通知的時候,任務將正常的執行下去,在所有任務都執行完成后,將 3 個請求結果輸出到控制臺中,同時銷毀任務釋放線程資源;最后,執行 cts.Cancel()取消令牌并釋放資源,最后一句代碼將輸出令牌的狀態。

1.2 執行程序,輸出結果

通過上面的輸出接口,可以看出,紅色部分是模擬請求,這個請求時多線程進行的,Post 和 Love 交替出現,是因為在程序中通過線程休眠的方式模擬網絡阻塞過程,藍色為合并結果部分,可以看到,雖然“文章信息”已經加載完成,但是因為 Post 和 Love 還在請求中,由于取消令牌未收到退出通知,所以合并結果會等待信號,在所有線程都執行完成后,通過 cts.Cancel() 通知令牌取消,所有事件執行完成,控制臺打印結果黃色部分為令牌狀態,顯示為 True ,令牌已取消。

2. 對長時間阻塞調用的異步取消令牌應用

在某些場景中,我們需要請求外部的第三方資源,比如請求天氣預報信息;但是,由于網絡等原因,可能會造成長時間的等待以致業務超時退出,這種情況可以使用 CancellationToken 來進行優化,但請求超過指定時長后退出,而不必針對每個 HttpClient 進行單獨的超時設置

2.1 獲取天氣預報

public async static Task GetToday(){CancellationTokenSource cts = new CancellationTokenSource();cts.CancelAfter(3000);HttpClient client = new HttpClient();var res = await client.GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts.Token);var result = await res.Content.ReadAsStringAsync();Console.WriteLine(result);cts.Dispose();client.Dispose();}

在上面的代碼中,首先定義了一個 CancellationTokenSource 對象,然后馬上發起了一個 HttpClient 的 GetAsync 請求(注意,這種使用 HttpClient 的方式是不正確的,詳見我的博客?HttpClient的演進和避坑?;在 GetAsync 請求中傳入了一個取消令牌,然后立即發起了退出請求 Console.WriteLine(result); 不管 3 秒后請求是否返回,都將取消令牌等待信號,最后輸出結果釋放資源

  • 注意:如果是因為取消令牌退出引起請求中斷,將會拋出任務取消的異常 TaskCanceledException
  • 執行程序輸出結果

3. CancellationToken 的鏈式反應

可以使用創建一組令牌,通過鏈接各個令牌,使其建立通知關聯,當 CancellationToken 鏈中的某個令牌收到取消通知的時候,由鏈式中創建出來的 CancellationToken 令牌也將同時取消

3.1 創建鏈式測試代碼

public async static Task Test(){CancellationTokenSource cts1 = new CancellationTokenSource();CancellationTokenSource cts2 = new CancellationTokenSource();var cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);cts1.Token.Register(() =>{Console.WriteLine("cts1 Canceling");});cts2.Token.Register(() =>{Console.WriteLine("cts2 Canceling");});cts2.CancelAfter(1000);cts3.Token.Register(() =>{Console.WriteLine("root Canceling");});var res = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts1.Token);var result = await res.Content.ReadAsStringAsync();Console.WriteLine("cts1:{0}", result);var res2 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts2.Token);var result2 = await res2.Content.ReadAsStringAsync();Console.WriteLine("cts2:{0}", result2);var res3 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts3.Token);var result3 = await res2.Content.ReadAsStringAsync();Console.WriteLine("cts3:{0}", result3);}

上面的代碼定義了 3 個 CancellationTokenSource ,分別是 cts1,cts2,cts3,每個 CancellationTokenSource 分別注冊了 Register 取消回調委托,然后,使用 HttpClient 發起 3 組網絡請求;其中,設置 cts2 在請求開始 1秒 后退出,預期結果為:當 cts2 退出后,由于 cts3 是使用 CreateLinkedTokenSource(cts1.Token, cts2.Token) 創建出來的,所以 cts3 應該也會被取消,實際上,無論 cts1/cts2 哪個令牌取消,cts3 都會被取消

3.2 執行程序,輸出結果

從上圖可以看到,紅色部分輸出結果是:首先 cts2 取消,接著產生了鏈式反應導致 cts3 也跟著取消,藍色部分為 cts1 的正常請求結果,最后輸出了任務退出的異常信息

4. CancellationToken 令牌取消的三種方式

CancellationToken 定義了三種不同的取消方法,分別是 Cancel(),CancelAfter(),Dispose();這三種方式都代表了不同的行為方式

4.1 演示取消動作

public static void Test(){CancellationTokenSource cts1 = new CancellationTokenSource();cts1.Token.Register(() =>{Console.WriteLine("\ncts1 ThreadId: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);});cts1.Cancel();Console.WriteLine("cts1 State:{0}", cts1.IsCancellationRequested);CancellationTokenSource cts2 = new CancellationTokenSource();cts2.Token.Register(() =>{Console.WriteLine("\ncts2 ThreadId: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);});cts2.CancelAfter(500);System.Threading.Thread.Sleep(1000);Console.WriteLine("cts2 State:{0}", cts2.IsCancellationRequested);CancellationTokenSource cts3 = new CancellationTokenSource();cts3.Token.Register(() =>{Console.WriteLine("\ncts3 ThreadId: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);});cts3.Dispose();Console.WriteLine("\ncts3 State:{0}", cts3.IsCancellationRequested);}

4.2 執行程序,輸出結果如下

上面的代碼定義了 3 個 CancellationTokenSource,分別是 cts1/cts2/cts3;分別執行了 3 中不同的取消令牌的方式,并在取消回調委托中輸出線程ID,從輸出接口中看出,當程序執行 cts1.Cancel() 方法后,取消令牌立即執行了回調委托,并輸出線程ID為:1;cts2.CancelAfter(500) 表示 500ms 后取消,為了獲得令牌狀態,這里使線程休眠了 1000ms,而 cts3 則直接調用了 Dispose() 方法,從輸出結果看出,cts1 運行在和 Main 方法在同一個線程上,線程 ID 都為 1,而 cts2 由于使用了延遲取消,導致其在內部新創建了一個線程,其線程 ID 為 4;最后,cts3由于直接調用了 Dispose() 方法,但是其 IsCancellationRequested 的值為 False,表示未取消,而輸出結果也表明,沒有執行回調委托

結束語

  • 通過本文,我們學習到了如何在不同的應用場景下使用 CancellationToken
  • 掌握了合并請求、中斷請求、鏈式反應 三種使用方式
  • 最后還了解到三種不同的取消令牌方式,知道了各種不同取消方式的區別

示例代碼下載

https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.ThreadingDemo

總結

以上是生活随笔為你收集整理的【转】1.9 Asp.Net Core 轻松学-多线程之取消令牌(的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。