博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
燃烧的CPU
阅读量:5937 次
发布时间:2019-06-19

本文共 5199 字,大约阅读时间需要 17 分钟。

hot3.png

假设现在有几个不同的任务需要排列进入线程池中执行,我如要在任务全部完成时通知这一批的客户,告诉他们交付的任务都已经完成了。但是如何才能知道线程有没有执行完成呢?

ThreadPool 提供的是静态方法,没有执行完成的 CallBack 之类的方法,但是 RegisterWaitForSingleObject 为我们提供了信号量,然后可以通过 System.Threading.WaitHandle.WaitAll 或者 WaitAny 去阻塞主线程,等待信号量的通知。

先创建一个信号量,命名的信号量可以在环境中进行查询获取

 EventWaitHandle ewHandle = new EventWaitHandle(false, EventResetMode.ManualReset, "EventWaitHandle" + i.ToString());

然后将信号量和执行任务的方法一起传递进入线程池中

 // 创建委托调用的方法 WaitOrTimerCallback wtCallback = new WaitOrTimerCallback(CalculateCallBack); // 加入线程池 cell 对象为自定义的执行单元对象,包含了 本次任务的相关数据和关联的信号量 ThreadPool.RegisterWaitForSingleObject(ewHandle, wtCallback, cell, 0, true);

在加入线程池后,主进程可以使用 Wait 方式等待线程池的执行

// 等待全部线程的完成通知System.Threading.WaitHandle.WaitAll(listHandle, Timeout.Infinite);

在任务执行完成后使用信号量发出通知,告诉主进程中的等待可以结束

 // 信号量的完成通知 cellState.WaitHandle.Set();

下面是一组测试图,使用线程池测试浮点数运算效率 【一万次随机的浮点数运算】

使用 4 个线程运算,使用了 80 秒, CPU 使用状态 保持在 60 % 上

175257_TuHB_559187.png

175011_DCUZ_559187.png

 

在单线程的计算时 ,使用了 70 秒,CPU 使用状态 保持在 40 % 上

175400_dRXq_559187.png175506_J7CZ_559187.png

所以,线程不是越多越来,对于单一内容的任务多线程反而会因线程调度造成巨大的效率和资源浪费。好吧,其实这个不是本文的重点,重点是MARK 一下在使用线程池时,如何利用信号量通知进程执行情况。

 

MARK 通过信号量可以知道线程的完成情况,最后直接简单贴上测试的代码

using System;using System.Threading;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            // 性能计算器            System.Diagnostics.Stopwatch sdsWatch = new System.Diagnostics.Stopwatch();            Random randomSeed = new Random();            sdsWatch.Start();            Int32 sumCount = 100000;            double threadCount = 1;            bool usedThread = false;            Console.WriteLine("请输入计算量:");            sumCount = Convert.ToInt32(Console.ReadLine().Trim());            Console.WriteLine("是否使用多线程测试?Y/N");            usedThread = Console.ReadLine().Trim().ToUpper() == "Y";            if (usedThread)            {                Console.WriteLine("请输入拟定的线程数:");                threadCount = Convert.ToInt32(Console.ReadLine().Trim());            }            Console.WriteLine("计算任务:" + sumCount + " ,线程数:" + threadCount);            Console.ReadLine();            // 保存信号量的列表用于后续的访问            EventWaitHandle[] listHandle = new EventWaitHandle[(int)threadCount];            for (int i = 0; i < threadCount; i++)            {                EventWaitHandle ewHandle = new EventWaitHandle(false,                     EventResetMode.ManualReset, "EventWaitHandle" + i.ToString());                listHandle[i] = ewHandle;                CalCell cell = new CalCell()                {                    Start = (int)(i / threadCount * sumCount),                    End = (int)((i + 1) / threadCount * sumCount),                    WaitHandle = ewHandle                };                //WaitCallback wCallback = new WaitCallback(CalculateCallBack);                //ThreadPool.QueueUserWorkItem(wCallback, cell);                WaitOrTimerCallback wtCallback = new WaitOrTimerCallback(CalculateCallBack);                ThreadPool.RegisterWaitForSingleObject(ewHandle, wtCallback, cell, 0, true);            }            // 等待全部线程的完成通知            System.Threading.WaitHandle.WaitAll(listHandle, Timeout.Infinite);            //此处也可以使用 WaitAny 和 SignalAndWait 可以考虑实现逐次通知 【个人感觉是有时间风险的】            //EventWaitHandle callBackCompleted =             //new EventWaitHandle(false, EventResetMode.ManualReset, "CompletedWaitHandle" + i.ToString());            //System.Threading.WaitHandle.SignalAndWait(callBackCompleted, ewHandle, Timeout.Infinite, true);            sdsWatch.Stop();            Console.WriteLine(string.Format("====== Calculate Tasks:{0,10}, Threads:{1,10} ===========",                sumCount, threadCount));            Console.WriteLine(string.Format("======    Milliseconds:{0,10},   Ticks:{1,10} ===========",                sdsWatch.ElapsedMilliseconds, sdsWatch.ElapsedTicks));            Console.ReadLine();        }        ///         /// 计算        ///         /// 
        private static void CalculateCallBack(object state)        {            CalCell cellState = (CalCell)state;            double value = 0.0D;            Random randomSeed = new Random();            for (int i = cellState.Start; i < cellState.End; i++)            {                value = i * randomSeed.NextDouble();                Console.WriteLine(string.Format("{0,-15:F6}Thread ID :{1}",                    value, Thread.CurrentThread.ManagedThreadId));            }        }        /// 
        /// 计算        ///         /// 
        private static void CalculateCallBack(object state, bool timeOut)        {            CalCell cellState = (CalCell)state;            double value = 0.0D;            Random randomSeed = new Random();            for (int i = cellState.Start; i < cellState.End; i++)            {                value = i * randomSeed.NextDouble();                Console.WriteLine(string.Format("{0,-15:F6}Thread ID :{1}",                    value, Thread.CurrentThread.ManagedThreadId));            }            // 信号量的完成通知            cellState.WaitHandle.Set();        }        /// 
        /// 计算单元        ///         public class CalCell        {            public int Start;            public int End;            public EventWaitHandle WaitHandle;        }    }}

转载于:https://my.oschina.net/HenuToater/blog/385752

你可能感兴趣的文章
P3041 [USACO12JAN]视频游戏的连击Video Game Combos
查看>>
CF1012C Hills
查看>>
男士必须收藏:男士健身方案
查看>>
03python面向对象编程2
查看>>
表格式布局让每个列高度等于该行最大高度
查看>>
Redis常用命令【字符串】
查看>>
ABP官方文档翻译 10.1 ABP Nuget包
查看>>
CentOS7 防火墙
查看>>
DataTable
查看>>
POJ 2226 Muddy Fields 二分图(难点在于建图)
查看>>
STM32软件仿真的一个注意点
查看>>
[LeetCode]题解(python):119-Pascal's Triangle II
查看>>
[LeetCode]题解(python):121-Best Time to Buy and Sell Stock
查看>>
Selenium-ActionChainsApi--鼠标连贯操作
查看>>
android基于MBR的bootkit病毒学习笔记
查看>>
Flask学习
查看>>
VC++文件操作大全
查看>>
队列的顺序存储---顺序队列
查看>>
NOIP
查看>>
MicroPython-GPS教程之TPYBoardv702控制5110显示当前经纬度
查看>>