CPU多核控速
初学者很多对自己开发的软件使用硬件资源的时候并不注意,造成写出的东西不是很满意。
一般有两种情况:
1.写的都是同步单线程任务,不管你电脑有多少个核都不关我事 我就用你1个核所以不管怎么样都不会把CPU吃满。
这样的例子还是比较多的,在CPU出多核之后很多软件陆续已经将这些问题进行了修复,不过也还有这样的情况。
拿我常用的金山快盘同步盘这个软件来说吧,他在要进行一次同步任务前要先下载一份服务器端文件版本信息的比对数据,所以当我点立即同步的时候或者刚打开软件的时候他会马上使用网络进行下载(任务管理器或很多流量监控软件都可以监控到),下载完成后进行文件版本对比任务找出需要更新的文件,这个时候在 任务管理器 里的进程中可以看到金山快盘会很快占用300-500M左右的内存(这个视个人电脑硬件配置和这个金山快盘用户文件多少而变化)CPU利用率立马飙到50%(我用的这台电脑是双核的)而且只有一个核的利用率到达很高另一个核在睡觉。这种状态一直持续很长一段时间不怎么变化(可能我的文件数量比较多所以这个时间就会比较长)。
2.多线程任务不控制CPU利用率。
很多朋友写程序的时候可能比较少用到多任务多线程开发 或者 搞不好这个程序中的多任务多线程只会用一会儿而且很快就能完成这个作业,所以用到的时候也没注意这么多。
经常使用多任务多线程开发的朋友应该是比较清楚的,不需要看这个了;
咱们先看一下控速与不控诉的区别,对比下面两张图就可以很明白的看出来了。
CPU不受控的情况下开启4条线程跑立马就把CPU吃满了,而且居高不下,造成电脑卡的不行无法进行别的作业。
受控的情况:
看完图就很明白情况了吧!代码是最好交流的方式,那咱们来看一下代码:
基本任务接口:
public interface ICpuManagementTask
{
void DoWork();
void DoWork(object a);
}
ICpuManagementTask
模拟作业,实现任务接口进行作业:
public class ApplictionClass : ICpuManagementTask
{ public ApplictionClass(out ICpuManagementTask icmt)
{
icmt = this;
} public void DoWork()
{
// Thread Code
do
{
int a = ;
for (int i = ; i < ; i++)
{
a = i;
}
//System.Threading.Thread.Sleep(1);
//Console.WriteLine("Task is Running " + mesg + "Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId); } while (true);
} public void DoWork(object mesg)
{
// Thread Code
do
{
int a = ;
for (int i = ; i < ; i++)
{
a = i;
}
//System.Threading.Thread.Sleep(1);
//Console.WriteLine("Task is Running " + mesg + "Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId); } while (true);
}
}
模拟基本业务
模拟不受控实现方式:
/// <summary>
/// 不受控的异步执行
/// </summary>
public void Test1(ICpuManagementTask icmt)
{
System.Threading.Tasks.Task T1 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T1.Start(); System.Threading.Tasks.Task T2 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T2.Start(); System.Threading.Tasks.Task T3 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T3.Start(); System.Threading.Tasks.Task T4 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T4.Start(); }
不受控TEST
前面这些都是很简单的,有点OO思想的一看就明白了不需要什么解释的。
既然要让任务占用硬件资源受控制那肯定是需要一些处理的,要跑的作业相当于托管在一个“容器”里面暂时叫他“自动管理CPU”吧,接下来先看一下这个“容器”

看到这个就很简单了吧!其实并没有什么神秘的,无非就是做两个事 一、创建任务 二、管理CPU使用率进行任务作业
咱们一个个看,首先看看这个枚举,他是自定义的几个模式对应当需要挂起线程时处理的事
public enum CpuManagementModelEnum
{
None, /// <summary>
/// 中断模式 允许自动关闭一下获得任务释放CPU资源
/// </summary>
BreakModel, /// <summary>
/// 睡眠模式 允许将活动任务设置为睡眠状态是否CPU资源
/// </summary>
SleepModel
}
管理模式枚举
public virtual void CreatParallelTask(Dictionary<Thread, object> list)
{
Action act = new Action(() =>
{
list.ToList().ForEach(a => a.Key.Priority = ThreadPriority.Lowest);
foreach (var item in list)
{
item.Key.Start(item.Value);
//break;
}
});
System.Threading.Tasks.ParallelOptions options = new System.Threading.Tasks.ParallelOptions();
options.MaxDegreeOfParallelism =list.Count ;
System.Threading.Tasks.Parallel.Invoke(options, new Action[] { act });
}
创建任务
创建任务也没什么比较难懂东西,就是把任务集合中的任务先用Action封装成方法 然后用System.Threading.Tasks.Parallel.Invoke 方法尽可能并行执行提供的每个操作。
后面这个控制并执行就有点复杂了,先看一下代码:
public virtual void CpuManagement(Dictionary<Thread, object> task, float cpuUpper, CpuManagementModelEnum cm)
{
Console.WindowWidth = ;
Thread t = new Thread(() =>
{
float avgCpu = ;
PerformanceCounter[] counters = new PerformanceCounter[System.Environment.ProcessorCount];
for (int i = ; i < counters.Length; i++)
{
counters[i] = new PerformanceCounter("Processor", "% Processor Time", i.ToString());
} while (true)
{
avgCpu = ;
for (int i = ; i < counters.Length; i++)
{
float f = counters[i].NextValue();
avgCpu += f;
}
avgCpu = avgCpu / counters.Length; if (avgCpu >= cpuUpper)
{
Console.Write("Sleep CPU-AVG: "
+ Math.Round(avgCpu, ).ToString().PadLeft(, ' ') + "%"
+ " CoreCount:" + counters.Length
+ " BusyThreadCount:" + task.Count(a => a.Key.ThreadState == System.Threading.ThreadState.Running).ToString()
+ " ThreadTotalCount:" + task.Count);
foreach (var item in task)
{
if (item.Key.ThreadState != System.Threading.ThreadState.Suspended)
{
item.Key.Suspend();
switch (cm)
{
case CpuManagementModelEnum.None:
break;
case CpuManagementModelEnum.BreakModel:
break;
case CpuManagementModelEnum.SleepModel:
System.Threading.Thread.Sleep();
break;
default:
break;
}
}
}
Console.Write(" Wait... \r\n");
}
else
{
Console.Write("Run CPU-AVG: " + Math.Round(avgCpu, ).ToString().PadLeft(, ' ') + "%"
+ " CoreCount:" + counters.Length
+ " BusyThreadCount:" + task.Count(a => a.Key.ThreadState == System.Threading.ThreadState.Running).ToString()
+ " ThreadTotalCount:" + task.Count);
foreach (var item in task)
{
if (item.Key.ThreadState == System.Threading.ThreadState.Suspended)
{
item.Key.Resume();
switch (cm)
{
case CpuManagementModelEnum.None:
break;
case CpuManagementModelEnum.BreakModel:
break;
case CpuManagementModelEnum.SleepModel:
System.Threading.Thread.Sleep();
break;
default:
break;
}
}
}
Console.Write(" Buy... \r\n");
}
System.Threading.Thread.Sleep();
}
});
t.Priority = ThreadPriority.Highest;
t.Start();
}
CPU管理执行任务
这里面主要就是做两个事:一、是对整体CPU资源被占用超过一个基数的时候要对现有的任务管理集合中的任务进行挂起操作;
二、是对整体CPU资源被占用小于定的基数的时候 继续已挂起的线程;
这个方法的第二个参数就是咱们想设定的CPU资源被占用到多大的基数上限开始使这时候运行的程序挂起部分线程释放资源,比如你想让CPU保持在90%左右,留有一部分空间来处理别的进程突发占用的情况或者别的情况这要视场景而定了。
在这执行任务当中用到两个已经过时的API:
System.Threading.Thread中的Suspend和Resume ,看到msdn上的有个警告
大概是说如果使用挂起的话当这个线程正好持有锁的话这个AppDomain的其他线程很可能都被堵死了,或者是在挂起一个线程在执行一个类的构造函数这个AppDomin其他线程使用这个类会受阻。很容易发生死锁现象。

可能主要就是这个原因吧!有知道比较详细的朋友可以留言告诉我,大家互相学习嘛。。。
这两个方法上倒是写了一些:
关于解决死锁问题直接使用 System.Threading.Monitor 会更好,这里主要介绍CPU多核控速问题,所以上面代码就不修改了。这个关于多线程上的五种基本问题之一的 死锁 在这就不详细讨论了。
下面咱们再回头看一下 这种受控制的情况下如何在应用程序中实现:
/// <summary>
/// 受控的并行执行
/// </summary>
/// <param name="icmt"></param>
public void Test2(ICpuManagementTask icmt)
{
AutomaticCpuManagement CPU = new AutomaticCpuManagement(); Dictionary<Thread, object> task = new Dictionary<Thread, object>();
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now);
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds());
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds());
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds()); CPU.CreatParallelTask(task);
CPU.CpuManagement(task, 90F, AutomaticCpuManagement.CpuManagementModelEnum.BreakModel);
}
受控制实现
启动调试 的两条代码:
static void Main(string[] args)
{
ICpuManagementTask icmt;
ApplictionClass app = new ApplictionClass(out icmt); // app.Test1(icmt);
//Console.ReadKey(); app.Test2(icmt);
Console.ReadKey();
}
启动调试
分别调试两种方式进行观察就得到开头所看到的占用硬件资源不同的情况了。
CPU多核控速的更多相关文章
- paip.提升性能---mysql 优化cpu多核以及lan性能的关系.
paip.提升性能---mysql 优化cpu多核以及lan性能的关系. 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http:/ ...
- R语言的并行运算(CPU多核)
通常R语言运行都是在CPU单个核上的单线程程序.有时我们会有需求对一个向量里的元素应用相同的函数,最终再将结果合并,并行计算可以大幅节约时间. 为了支持R的并行运算, parallel包已经被纳入了R ...
- CPU 多核指令 —— WFE 原理【原创】
转自:http://tinylab.org/arm-wfe/ Zhang Binghua 创作于 2020/05/19 打赏 微信公众号 知识星球 关注 @泰晓科技 与数千位一线 Linux 工程 ...
- Msbuild利用cpu多核加速
msbuild /t:Rebuild /p:Configuration=Release /m /m 自动检测cpu数量启动对应数量进程
- 充分利用CPU多核的处理能力 innodb_read_io_threads和innodb_write_io_threads
https://book.2cto.com/201402/40300.html 在MySQL5.1.X版本中,innodb_file_io_threads参数默认是4,该参数在Linux系统上是不可更 ...
- Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity) 转
硬件中断发生频繁,是件很消耗 CPU 资源的事情,在多核 CPU 条件下如果有办法把大量硬件中断分配给不同的 CPU (core) 处理显然能很好的平衡性能.现在的服务器上动不动就是多 CPU 多核. ...
- 多CPU,多核,多进程,多线程
当面临这些问题的时候,有两个关键词无法绕开,那就是并行和并发. 首先,要先了解几个概念: 1.进程是程序的一次执行. 2.进程是资源分配的基本单位(调度单位). 3.一个进程可以包括多个线程. 4.在 ...
- 软件设计师考试计算机系统知识——CPU
第一章: 计算机系统知识 1.1.1计算机系统硬件的基本组成 运算器.控制器.存储器.输入设备.输出设备 1.1.2 中央处理器 ①CPU的功能: a.程序控制:CPU通过执行指令来控制程序执行的顺序 ...
- cpu 性能
我们平时使用的CPU利用率方法是极具误导性的,并且一年更甚一年.那么什么是CPU利用率?是你的CPU到底有多忙,是像“% CPU”这样到处在用的指标所显示的那样吗? 在top命令里,你看到90%的CP ...
随机推荐
- js取json对象的键和值
//构建一个json对象 var pinpai = { "0":{"美的":49,"三星":35,"海信":25,&qu ...
- Quartz 在线Cron表达式
Quartz自己配置Cron好麻烦,下面是一个在线Cron表达式生成器的网站,非常方便,现在使用Cron时基本上就直接用这个了. http://cron.qqe2.com/ Cron表达式 cronE ...
- 将gdal源码转化为VS工程编译过程记录
作者:朱金灿 来源:http://blog.csdn.net/clever101 为什么要用VS工程的方式来编译gdal库?主要还是为了调试方便,虽然理论上使用命令行方式生成库也能调试,详见:GDAL ...
- 获取当前div中的所有div的个数和每一个div的ID and 根据屏幕分辨率计算高度
var tabs_Count=document.getElementById("tabs-panels").getElementsByTagName("div" ...
- 2.RabbitMQ的quick start
1.首先要安装 RabbitMQ Client 2.创建一个控制台项目 取名 Publisher代码如下: using RabbitMQ.Client; using System; using Sys ...
- 百度地图 JavaScript API 极速版 开发体会
前段时间百度地图API推出了 JavaScript API 极速版 1.0 简单看了一下,从产品定位来说真是挺好. 把开发人员细分成普通web开发人员和移动web开发人员.正好用到了手机地图这块决定尝 ...
- AVL 树的插入、删除、旋转归纳
参考链接: http://blog.csdn.net/gabriel1026/article/details/6311339 1126号注:先前有一个概念搞混了: 节点的深度 Depth 是指从根 ...
- wpf中的倒影效果实现
原文:wpf中的倒影效果实现 <TextBox Name="txt" FontSize="30" ...
- 通过浏览器调用Android要么iOS应用
在做移动应用的单点登录时间,需要点击浏览器中启动链接APP和参数传递APP其中,用于处理相应的接口,现在,通过浏览器调用Android和iOS在应用过程中实现理清固化博客.为了查询. 一:通过浏览器调 ...
- [科普]MinGW vs MinGW-W64及其它(比较有意思,来自mingw吧)
部分参照备忘录原文: bitbucket.org/FrankHB/yslib/src/50c3e6344a5a24b2382ce3398065f2197c2bd57e/doc/Workflow.Ann ...