C#多线程之线程池篇2
在上一篇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”方法来注册一个异步操作被取消时被调用的回调方法。这种方式可以允许我们将取消操作的逻辑链接到另一个异步操作中。
转载于:https://www.cnblogs.com/yonghuacui/p/6226537.html
C#多线程之线程池篇2相关推荐
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- Java多线程之线程池详解
Java多线程之线程池详解 目录: 线程池使用及优势 线程池3个常用方式 线程池7大参数深入介绍 线程池底层工作原理 1. 线程池使用及优势 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务 ...
- 一篇就够,线程与线程池的那些事之线程池篇
本文关键字: 线程 , 线程池 , 单线程 , 多线程 , 线程池的好处 , 线程回收 , 创建方式, 核心参数 , 底层机制 , 拒绝策略 , 参数设置 , 动态监控 , 线程隔离 线程和线程池相关 ...
- java多线程之线程池简介
前言 池化技术已经屡见不鲜了,比如数据库连接池,大家的项目中应该也用到了线程池.池化技术的好处:降低资源的消耗,提高响应速度,提高线程的可管理性.本篇主要是和大家一起分析下线程池的架构和它的工作流程. ...
- JUC源码分析-线程池篇(五):ForkJoinPool - 2
通过上一篇(JUC源码分析-线程池篇(四):ForkJoinPool - 1)的讲解,相信同学们对 ForkJoinPool 已经有了一个大概的认识,本篇我们将通过分析源码的方式来深入了解 ForkJ ...
- 面试必问:多线程与线程池
前言 前几章都在讲一些锁的使用和原理,主要是为了保证多线程情况下变量的原子性,但这并不是说多线程不好,合理利用还是有好处的.至于什么好处,看下面内容就懂了,先打个比方吧(谁叫比方,上来挨打):假如你体 ...
- Java多线程估算线程池
原理 多线程的线程池可以提高程序的运行性能,这是毋庸置疑的,但是如何设置线程池的大小,以前一直是靠猜,或者根据经验配置,这两天对系统的线程池进行优化配置时,找到了如何合理地估算线程池大小这篇文章,在这 ...
- Java的多线程和线程池的使用,你真的清楚了吗?
Java的多线程和线程池的使用 多线程大大提高程序运行效率,我们在开发过程中经常会开启一个线程来执行一些费时的任务.开启一个线程有4种方式,在下面的文章我将详细的去讲解. 继承Thread 继承Thr ...
- 多线程之线程池-各个参数的含义- 阿里,美团,京东面试题目
阿里的面试官问了个问题,如果corepollSize=10,MaxPollSize=20,如果来了25个线程 怎么办, 答案: 当一个任务通过execute(Runnable)方法欲添加到线程池时: ...
最新文章
- 图解Istio原理和实践--云平台技术栈18
- bootstrap 横铺 行_Bootstrap 排版
- mysql修改默认编码为UTF8
- GDCM:gdcm::Spacing的测试程序
- JSP 中EL表达式用法详解
- ssh时,密码输入框(密码输入提示)很晚才出现的解决方法
- 大话设计模式读书笔记(十三) 状态模式
- 硬件基础知识---(15) 二极管单项导电特性
- CentOS6.5 webserver---网络配置
- VS1.4挤房+MH的登陆器
- CUDA基础教程(2):费米架构
- 2019年美赛获奖分享经验
- 词根词缀的实践应用 - 词根词缀词典墨墨详细使用
- 小程序体验版二维码进入请求超时
- 用Python摘抄《大道争锋》中的诗句
- Cousera- software security
- 地鼠君黑盒测试--小白功能测试避雷经验分享
- [php] thinkphp实现 163 qq 邮箱收发邮件(切实可用)
- 响应式布局之微软商城部分开发
- Visio 2010、2013中找不到“拆分”,“联合”,“相交”等开发工具