在上一篇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. ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面

    DefaultFilesMiddleware中间件的目的在于将目标目录下的默认文件作为响应内容.我们知道,如果直接请求的就是这个默认文件,那么前面介绍的StaticFileMiddleware中间件会 ...

  2. 更愉快的书写CSS

    我在写CSS的时候经常会碰到些麻烦事儿: 1)看上去蛮简单的排版却写了很久 2)代码写的越来越散,总是这里补一句,那里补一句,没有条理性 3)margin.padding.font-size等属性在不 ...

  3. SQL Server2008R2 在windows8上安装,出现“兼容性”和 “执行未经授权的操作”的错误!

    本人是windows8.1的操作系统,亲测安装成功 解决方法如下: 1.卸载干净sql Server2008r2,包括注册表内容,删除c盘下的安装路径! 2.关闭防火墙(这步很重要) 3.断开网络连接 ...

  4. 创建ABPboilerplate模版项目

    本文是根据角落的白板报的<通过ABPboilerplate模版创建项目>一文的学习总结,感谢原文作者角落的白板报. 1 准备 开发环境: Visual Studio 2015 update ...

  5. 微信小程序开发—快速掌握组件及API的方法

    微信小程序框架为开发者提供了一系列的组件和API接口. 组件主要完成小程序的视图部分,例如文字.图片显示.API主要完成逻辑功能,例如网络请求.数据存储.音视频播放控制,以及微信开放的微信登录.微信支 ...

  6. 微信小程序体验(1):携程酒店机票火车票

    在 12 月 28 日微信公开课上,张小龙对微信小程序的形态进行了阐释,小程序有四个特定:无需安装.触手可及.用完即走.无需卸载. 由于携程这种订酒店.火车票和机票等工具性质非常强的服务,非常符合张小 ...

  7. SQL数据类型

    1.Character 字符串: 数据类型 描述 存储 char(n) 固定长度的字符串.最多8,000个字符. n varchar(n) 可变长度的字符串.最多8,000个字符.   varchar ...

  8. ubuntu系统(华硕笔记本)屏幕亮度用Fn控制的调节设置

    亲测配置: 系统:Linux lite 3.2 x86_64(Ubuntu其他版本可参考修改) 笔记本:华硕(asus)1201N 达到的效果: 可以正常使用Fn+F5调暗,Fn+F6调亮. 设置步骤 ...

  9. [每日Linux]Linux下xsell和xftp的使用

    实验缘由: 1.xsell在Linux下的作用就是远程登录的一个界面,也就是实现访问在Windows下访问Linux服务器的功能.之前在数据挖掘实验中因为自己电脑的内存不够,曾经使用过实验室的服务器跑 ...

  10. 解除win7网络限速.

    在电脑刚买或者系统重装了的时候,win7系统会默认限制20%的网络速度,限制了我们的上网速度,我们可以解决这个限制,让上网变得更快 下面是操作步骤 1.开始>运行 2.输入以下命令,然后确定 g ...