C#多線程之線程池篇2

来源:http://www.cnblogs.com/yonghuacui/archive/2016/12/28/6226537.html
-Advertisement-
Play Games

在上一篇C#多線程之線程池篇1中,我們主要學習瞭如何線上程池中調用委托以及如何線上程池中執行非同步操作,在這篇中,我們將學習線程池和並行度、實現取消選項的相關知識。 三、線程池和並行度 在這一小節中,我們將學習對於大量的非同步操作,使用線程池和分別使用單獨的線程在性能上有什麼差異性。具體操作步驟如下: ...


  在上一篇C#多線程之線程池篇1中,我們主要學習瞭如何線上程池中調用委托以及如何線上程池中執行非同步操作,在這篇中,我們將學習線程池和並行度、實現取消選項的相關知識。

三、線程池和並行度

  在這一小節中,我們將學習對於大量的非同步操作,使用線程池和分別使用單獨的線程在性能上有什麼差異性。具體操作步驟如下:

1、使用Visual Studio 2015創建一個新的控制台應用程式。

2、雙擊打開“Program.cs”文件,編寫代碼如下所示:

 1 using System;
 2 using System.Diagnostics;
 3 using System.Threading;
 4 using static System.Console;
 5 using static System.Threading.Thread;
 6 
 7 namespace Recipe03
 8 {
 9     class Program
10     {
11         static void UseThreads(int numberOfOperations)
12         {
13             using(var countdown=new CountdownEvent(numberOfOperations))
14             {
15                 WriteLine("Scheduling work by creating threads");
16                 for(int i = 0; i < numberOfOperations; i++)
17                 {
18                     var thread = new Thread(() =>
19                       {
20                           Write($"{CurrentThread.ManagedThreadId},");
21                           Sleep(100);
22                           countdown.Signal();
23                       });
24                     thread.Start();
25                 }
26                 countdown.Wait();
27                 WriteLine();
28             }
29         }
30 
31         static void UseThreadPool(int numberOfOperations)
32         {
33             using(var countdown=new CountdownEvent(numberOfOperations))
34             {
35                 WriteLine("Starting work on a threadpool");
36                 for(int i = 0; i < numberOfOperations; i++)
37                 {
38                     ThreadPool.QueueUserWorkItem(_ =>
39                     {
40                         Write($"{CurrentThread.ManagedThreadId},");
41                         Sleep(100);
42                         countdown.Signal();
43                     });
44                 }
45                 countdown.Wait();
46                 WriteLine();
47             }
48         }
49 
50         static void Main(string[] args)
51         {
52             const int numberOfOperations = 500;
53             var sw = new Stopwatch();
54             sw.Start();
55             UseThreads(numberOfOperations);
56             sw.Stop();
57             WriteLine($"Execution time using threads: {sw.ElapsedMilliseconds}");
58 
59             sw.Reset();
60             sw.Start();
61             UseThreadPool(numberOfOperations);
62             sw.Stop();
63             WriteLine($"Execution time using the thread pool: {sw.ElapsedMilliseconds}");
64         }
65     }
66 }

3、運行該控制台應用程式,運行效果(每次運行效果可能不同)如下圖所示:

  在上述代碼中,我們首先創建了500個線程來執行非同步操作,我們發現使用每個單獨的線程執行非同步操作所消耗的時間為175毫秒。然後我們使用線程池來執行500個非同步操作,我們發現所消耗的時間為9432毫秒。這說明使用線程池來執行大併發的非同步操作會節省操作系統的記憶體和線程數,但是會嚴重影響應用程式的性能。

四、實現取消選項

  在這一小節中,我們將學習如何線上程池中取消一個非同步操作。具體步驟如下所示:

1、使用Visual Studio 2015創建一個新的控制台應用程式。

2、雙擊打開“Program.cs”文件,編寫代碼如下所示:

  1 using System;
  2 using System.Threading;
  3 using static System.Console;
  4 using static System.Threading.Thread;
  5 
  6 namespace Recipe04
  7 {
  8     class Program
  9     {
 10         // CancellationToken:傳播有關應取消操作的通知。
 11         static void AsyncOperation1(CancellationToken token)
 12         {
 13             WriteLine("Starting the first task");
 14             for (int i = 0; i < 5; i++)
 15             {
 16                 // IsCancellationRequested:獲取是否已請求取消此標記。
 17                 // 如果已請求取消此標記,則為 true,否則為 false。
 18                 if (token.IsCancellationRequested)
 19                 {
 20                     WriteLine("The first task has been canceled.");
 21                     return;
 22                 }
 23                 Sleep(TimeSpan.FromSeconds(1));
 24             }
 25             WriteLine("The first task has completed succesfully");
 26         }
 27 
 28         static void AsyncOperation2(CancellationToken token)
 29         {
 30             try
 31             {
 32                 WriteLine("Starting the second task");
 33                 for (int i = 0; i < 5; i++)
 34                 {
 35                     // 如果已請求取消此標記,則引發 System.OperationCanceledException。
 36                     token.ThrowIfCancellationRequested();
 37                     Sleep(TimeSpan.FromSeconds(1));
 38                 }
 39                 WriteLine("The second task has completed succesfully");
 40             }
 41             catch (OperationCanceledException)
 42             {
 43                 WriteLine("The second task has been canceled.");
 44             }
 45         }
 46 
 47         static void AsyncOperation3(CancellationToken token)
 48         {
 49             bool cancellationFlag = false;
 50             // 註冊一個將在取消此 System.Threading.CancellationToken 時調用的委托。
 51             // Register的參數是一個Action類型的委托,該委托在取消 System.Threading.CancellationToken 時執行
 52             token.Register(() => cancellationFlag = true);
 53             WriteLine("Starting the third task");
 54             for (int i = 0; i < 5; i++)
 55             {
 56                 if (cancellationFlag)
 57                 {
 58                     WriteLine("The third task has been canceled.");
 59                     return;
 60                 }
 61                 Sleep(TimeSpan.FromSeconds(1));
 62             }
 63             WriteLine("The third task has completed succesfully");
 64         }
 65 
 66         static void Main(string[] args)
 67         {
 68             // CancellationTokenSource:通知 System.Threading.CancellationToken,告知其應被取消。
 69             using (var cts = new CancellationTokenSource())
 70             {
 71                 // 獲取與此 System.Threading.CancellationTokenSource 關聯的 System.Threading.CancellationToken。
 72                 CancellationToken token = cts.Token;
 73                 ThreadPool.QueueUserWorkItem(_ => AsyncOperation1(token));
 74                 Sleep(TimeSpan.FromSeconds(2));
 75                 // 傳達取消請求。
 76                 cts.Cancel();
 77             }
 78 
 79             // CancellationTokenSource:通知 System.Threading.CancellationToken,告知其應被取消。
 80             using (var cts = new CancellationTokenSource())
 81             {
 82                 // 獲取與此 System.Threading.CancellationTokenSource 關聯的 System.Threading.CancellationToken。
 83                 CancellationToken token = cts.Token;
 84                 ThreadPool.QueueUserWorkItem(_ => AsyncOperation2(token));
 85                 Sleep(TimeSpan.FromSeconds(2));
 86                 // 傳達取消請求。
 87                 cts.Cancel();
 88             }
 89 
 90             // CancellationTokenSource:通知 System.Threading.CancellationToken,告知其應被取消。
 91             using (var cts = new CancellationTokenSource())
 92             {
 93                 // 獲取與此 System.Threading.CancellationTokenSource 關聯的 System.Threading.CancellationToken。
 94                 CancellationToken token = cts.Token;
 95                 ThreadPool.QueueUserWorkItem(_ => AsyncOperation3(token));
 96                 Sleep(TimeSpan.FromSeconds(2));
 97                 // 傳達取消請求。
 98                 cts.Cancel();
 99             }
100 
101             Sleep(TimeSpan.FromSeconds(2));
102         }
103     }
104 }

3、運行該控制台應用程式,運行效果如下圖所示:

  在上述代碼中,我們使用了CancellationTokenSource和CancellationToken類,這兩個類在.NET 4.0引入,現在已經成為取消非同步操作事實上的標準。

  在“AsyncOperation1”方法中,我們僅僅是輪詢檢查“CancellationToken.IsCancellationRequested”屬性,如果該屬性為true,這意味著我們的操作已被取消,我們必須放棄此次操作。

  在“AsyncOperation2”方法中,我們調用CancellationToken的“ThrowIfCancellationRequested”方法來檢查操作是否已被取消,如果已被取消,該方法會拋出OperationCanceledException異常,我們使用try/catch塊捕獲這個異常來中止非同步操作的執行。

  在“AsyncOperation3”方法中,我們調用CancellationToken的“Register”方法來註冊一個非同步操作被取消時被調用的回調方法。這種方式可以允許我們將取消操作的邏輯鏈接到另一個非同步操作中。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 軟體環境 vs2015 asp.net mvc 5 .NET Framework 4.5.2 AutoMapper 5.2.0.0 AutoMapper安裝 新建asp.net mvc 項目 AutoMapperExample,此處應該都會用vs新建mvc項目了,不再講解如何創建 , 點擊 工具→N ...
  • 使用IdentityServer4 實現OpenID Connect服務端,添加用戶身份驗證。客戶端調用,實現授權。 IdentityServer4 目前已更新至1.0 版,在之前的文章中有所介紹。IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2 ...
  • 參考資料: http://blog.csdn.net/bitfan/article/details/4438458 所謂記憶體映射文件,其實就是在記憶體中開闢出一塊存放數據的專用區域,這區域往往與硬碟上特定的文件相對應。進程將這塊記憶體區域映射到自己的地址空間中,訪問它就象是訪問普通的記憶體一樣。 在.NE ...
  • 一.母板頁_Layout.cshtml類似於傳統WebForm中的.master文件,起到頁面整體框架重用的目地1.母板頁代碼預覽 2.子頁面標題的設置雖然多個子頁面可以引用同一個母板頁,但不同的頁面標題可以單獨設置。@ViewBag.Title 即是一個標題的占位符,在Control里或頁面中給該 ...
  • 新工作入職不滿半周,目前仍然還在交接工作,適應環境當中,筆者不得不說看別人的源碼實在是令人痛苦。所幸今天終於將大部分工作流暢地看了一遍,接下來就是熟悉框架技術的階段了。 也正是在看源碼的過程當中,有一個比較明顯的用法細節引起了我的註意,我發現一位同事在請求遠程Web Api時,雖然使用了 類,但是在 ...
  • 快速開發相對於其他開發方式有什麼優勢?能為你節省多少成本? ...
  • VS項目中使用Nuget還原包後編譯生產還一直報錯? ...
  • 申請博客 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...