在上一篇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 = ; i < numberOfOperations; i++)
  17. {
  18. var thread = new Thread(() =>
  19. {
  20. Write($"{CurrentThread.ManagedThreadId},");
  21. Sleep();
  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 = ; i < numberOfOperations; i++)
  37. {
  38. ThreadPool.QueueUserWorkItem(_ =>
  39. {
  40. Write($"{CurrentThread.ManagedThreadId},");
  41. Sleep();
  42. countdown.Signal();
  43. });
  44. }
  45. countdown.Wait();
  46. WriteLine();
  47. }
  48. }
  49.  
  50. static void Main(string[] args)
  51. {
  52. const int numberOfOperations = ;
  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 = ; i < ; 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());
  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 = ; i < ; i++)
  34. {
  35. // 如果已请求取消此标记,则引发 System.OperationCanceledException。
  36. token.ThrowIfCancellationRequested();
  37. Sleep(TimeSpan.FromSeconds());
  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 = ; i < ; i++)
  55. {
  56. if (cancellationFlag)
  57. {
  58. WriteLine("The third task has been canceled.");
  59. return;
  60. }
  61. Sleep(TimeSpan.FromSeconds());
  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());
  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());
  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());
  97. // 传达取消请求。
  98. cts.Cancel();
  99. }
  100.  
  101. Sleep(TimeSpan.FromSeconds());
  102. }
  103. }
  104. }

3、运行该控制台应用程序,运行效果如下图所示:

  在上述代码中,我们使用了CancellationTokenSource和CancellationToken类,这两个类在.NET 4.0引入,现在已经成为取消异步操作事实上的标准。

  在“AsyncOperation1”方法中,我们仅仅是轮询检查“CancellationToken.IsCancellationRequested”属性,如果该属性为true,这意味着我们的操作已被取消,我们必须放弃此次操作。

  在“AsyncOperation2”方法中,我们调用CancellationToken的“ThrowIfCancellationRequested”方法来检查操作是否已被取消,如果已被取消,该方法会抛出OperationCanceledException异常,我们使用try/catch块捕获这个异常来中止异步操作的执行。

  在“AsyncOperation3”方法中,我们调用CancellationToken的“Register”方法来注册一个异步操作被取消时被调用的回调方法。这种方式可以允许我们将取消操作的逻辑链接到另一个异步操作中。

C#多线程之线程池篇2的更多相关文章

  1. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  2. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

  3. JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

    JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor.它主要用来在 ...

  4. Qt中的多线程与线程池浅析+实例

    1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...

  5. Java 多线程:线程池

    Java 多线程:线程池 作者:Grey 原文地址: 博客园:Java 多线程:线程池 CSDN:Java 多线程:线程池 工作原理 线程池内部是通过队列结合线程实现的,当我们利用线程池执行任务时: ...

  6. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

  7. C#多线程之线程同步篇2

    在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...

  8. 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

  9. ExecutorService 建立一个多线程的线程池的步骤

    ExecutorService 建立一个多线程的线程池的步骤: 线程池的作用: 线程池功能是限制在系统中运行的线程数. 依据系统的环境情况,能够自己主动或手动设置线程数量.达到执行的最佳效果:少了浪费 ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

    阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...

  2. Sql Server系列:分区表操作

    1. 分区表简介 分区表在逻辑上是一个表,而物理上是多个表.从用户角度来看,分区表和普通表是一样的.使用分区表的主要目的是为改善大型表以及具有多个访问模式的表的可伸缩性和可管理性. 分区表是把数据按设 ...

  3. 谈一下关于CQRS架构如何实现高性能

    CQRS架构简介 前不久,看到博客园一位园友写了一篇文章,其中的观点是,要想高性能,需要尽量:避开网络开销(IO),避开海量数据,避开资源争夺.对于这3点,我觉得很有道理.所以也想谈一下,CQRS架构 ...

  4. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  5. .Net Core MVC 网站开发(Ninesky) 2.2、栏目管理功能-System区域添加

    在asp或asp.net中为了方便网站的结构清晰,通常把具有类似功能的页面放到一个文件夹中,用户管理功能都放在Admin文件夹下,用户功能都放在Member文件夹下,在MVC中,通常使用区域(Area ...

  6. Kooboo CMS技术文档之二:Kooboo CMS的安装步骤

    在IIS上安装Kooboo CMS Kooboo CMS安装之后 安装的常见问题 1. 在IIS上安装Kooboo CMS Kooboo CMS部署到正式环境相当简单,安装过程是一个普通MVC站点在I ...

  7. WPF中Grid实现网格,表格样式通用类

    /// <summary> /// 给Grid添加边框线 /// </summary> /// <param name="grid"></ ...

  8. maven依赖查询地址

    http://search.maven.org/#search%7Cga%7C1%7C

  9. AEAI DP V3.7.0 发布,开源综合应用开发平台

    1  升级说明 AEAI DP 3.7版本是AEAI DP一个里程碑版本,基于JDK1.7开发,在本版本中新增支持Rest服务开发机制(默认支持WebService服务开发机制),且支持WS服务.RS ...

  10. iOS之解决崩溃Collection <__NSArrayM: 0xb550c30> was mutated while being enumerated.

    崩溃提示:Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <CAL ...