多线程编程学习笔记——线程池(二)
2018-06-17 22:28:03来源:未知 阅读 ()
接上文 多线程编程学习笔记——线程池(一)
三、线程池与并行度
此示例是学习如何应用线程池实现大量的操作,及与创建大量线程进行工作的区别。
1. 代码如下
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { class Program { static void Main(string[] args) { Console.WriteLine("开始测试线程池与自创线程。。。"); const int total = 500; long millisecondes = 0; Stopwatch sw = new Stopwatch(); sw.Start(); ThreadRun(total); sw.Stop(); millisecondes = sw.ElapsedMilliseconds; decimal mom = (decimal)(Environment.WorkingSet / (1024 * 1024.0)); sw.Reset(); sw.Start(); ThreadPoolRun(total); sw.Stop(); Console.WriteLine("自创线程总耗时 {0},占用内存:{1} MB", millisecondes,mom); Console.WriteLine("线程池总耗时 {0} ,占用内存:{1} MB", sw.ElapsedMilliseconds, Environment.WorkingSet / (1024 * 1024.0)); Console.Read(); } private static void ThreadRun(int total) { using (var countdown = new CountdownEvent(total)) { Console.WriteLine("开始--自创线程。。。"); for (int i = 0; i < total; i++) { var t = new Thread(() => { Console.WriteLine("自创线程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(0.1)); countdown.Signal();//向 CountdownEvent 注册信号,同时减小 CurrentCount 的值。 }); t.Start(); } countdown.Wait(); // 阻塞当前线程,直到 CountdownEvent 的信号数量变为 0 Console.WriteLine("-----------------"); } } private static void ThreadPoolRun(int total) { using (var countdown = new CountdownEvent(total)) { Console.WriteLine("开始--线程池。。。"); for (int i = 0; i < total; i++) { ThreadPool.QueueUserWorkItem(_ => { Console.WriteLine("线程池工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(0.1)); countdown.Signal();//向 CountdownEvent 注册信号,同时减小 CurrentCount 的值。 }); } countdown.Wait(); // 阻塞当前线程,直到 CountdownEvent 的信号数量变为 0 Console.WriteLine("-----------------"); } } } }
2.程序运行结果如下图。
1) 这个示例中我们自己创建了500个线程,每个线程一个操作,每个线程都阻塞100毫秒。总计耗时 11秒,消耗资源如下图。
2)我们使用线程池执行相同的500个操作。总计耗时 9秒,消耗资源如下图。
从1)与2)的比较上可以看出来,自创线程消耗的CPU资源比线程池要多。
四、 从线程池中取消操作
如果我们要从线程池中取消某个线程的操作,应该如何实现呢?本示例使用CancellationTokenSource和CancellationToken两个类来实现在取消线程池中的操作。这两个是是在net 4.0引入的。
1.示例代码
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; namespace ThreadPoolDemo { class Program { static void Main(string[] args) { Console.WriteLine("开始测试线程池中取消正在运行的线程。。。"); using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => AsyncOper(token)); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel();//取消线程操作 } using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => AsyncOperation(token)); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel();//取消线程操作 } using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => AsyncOper3(token)); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel();//取消线程操作 } Thread.Sleep(TimeSpan.FromSeconds(2)); Console.WriteLine("。。。。。。。。。。取消正在运行的线程结束。。。。。。"); Console.Read(); } private static void AsyncOperation(CancellationToken token) { try { Console.WriteLine("开始--线程池中的第二个工作线程。。。"); for (int i = 0; i < 5; i++) { token.ThrowIfCancellationRequested();//获取取消请求,抛出OperationCanceledException异常, Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("-------线程池中的第二个工作线程 工作完成----------"); } catch (OperationCanceledException ex) { Console.WriteLine("使用抛出异常方法取消第二个工作线程 ID:{0},{1}", Thread.CurrentThread.ManagedThreadId,ex.Message); } } private static void AsyncOper(CancellationToken token) { Console.WriteLine("开始--线程池中的第一个工作线程。。。"); for (int i = 0; i < 5; i++) { if (token.IsCancellationRequested)//判断是否已经取消操作 { Console.WriteLine("使用轮询方法取消工作线程 ID:{0}", Thread.CurrentThread.ManagedThreadId); return; } Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("-------线程池中的第一个工作线程 工作完成----------"); } private static void AsyncOper3(CancellationToken token) { Console.WriteLine("开始--线程池中的第三个工作线程。。。"); bool cancel = false; token.Register(()=>cancel = true); for (int i = 0; i < 5; i++) { if (cancel)//判断是否已经取消操作 { Console.WriteLine("通过注册回调函数取消第三个工作线程 ID:{0}", Thread.CurrentThread.ManagedThreadId); return; } Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("-------线程池中的第三个工作线程 工作完成----------"); } } }
2.运行结果如下图。
本示例一共实现了三种取消线程池中操作的方式。
- 轮询检查CancellationToken.IsCancellationRequested属性,如果为true,则说明操作被取消。
- 抛出一个OperationCancellationException异常。这允许操作之外的代码来取消操作。
- 注册一个回调函数,当操作取消时,线程池将调用回调函数,这样做的好处是将取消操作逻辑传递到另一个异步操作中。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- PHP进阶学习之垃圾回收机制详解 2019-10-09
- PHP语言好不好?优势在哪里? 2019-09-30
- Laravel学习:服务容器绑定与解析 2019-09-23
- 学习PHP到底要学习哪些东西? 2019-09-23
- 学习PHP的10个技巧 2019-09-23
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash