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 ...
随机推荐
- Word Break II -- leetcode
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...
- Java爬虫框架WebMagic入门——爬取列表类网站文章
初学爬虫,WebMagic作为一个Java开发的爬虫框架很容易上手,下面就通过一个简单的小例子来看一下. WebMagic框架简介 WebMagic框架包含四个组件,PageProcessor.Sch ...
- Android高度仿新浪微博引导页面
在写这一篇文章之前,先向大家推荐一篇博文:http://blog.csdn.net/dawanganban/article/details/17297671 感谢这位博主,我在该博主的基础上完成了对新 ...
- 利用WPF建立自己的3d gis软件(非axhost方式)(四)在地图上添加FrameworkElement
原文:利用WPF建立自己的3d gis软件(非axhost方式)(四)在地图上添加FrameworkElement 先下载SDK:https://pan.baidu.com/s/1M9kBS6ouUw ...
- Linode跨节点迁移:从Tokyo到Fremont
背景 上一篇博客交代了如何在 Linode 上搭建邮件服务器,并配置好各种协议.记录来投入实际使用. 由于实践过程中,曾经尝试使用明文协议与服务器交流数据,可能泄露了账号.密码信息,造成之后被攻击发送 ...
- Android能够获取到唯一的设备ID吗?
Android是否有唯一的设备ID,如果有的话,该怎样快速有效获取? Settings.Secure#ANDROID_ID 返回Android ID ,是一个64位的16进制字符串 1 2 3 imp ...
- WPF 自定义控件的坑(蠢的:自定义控件内容不显示)
原文:WPF 自定义控件的坑(蠢的:自定义控件内容不显示) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/koloumi/article/detai ...
- 西门子与三菱PLC报文比较
1.西门子和三菱的几个区别(上位只关心的通讯层面):1. 西门子PLC通讯端口固定102,但是可以连接多个PC端(客户端),三菱PLC通讯端口可以自定义,最多好像8个,但是每个端口只能连接一个客户端: ...
- RabbitMq核心概念和术语
简介 越来越多的消息中间件很容易让人产生混淆,在学习一种消息中间件的时候,最好先了解他的几种抽象概念,方便你理解,明白了这些概念,你学习起来的时候也就得心应手,同时也是使用好RabbitMQ的基础. ...
- WPF中取得系统字体列表
原文:WPF中取得系统字体列表 在GDI+中,我们可以通过如下方式取得系统所有字体: foreach(FontFamily f in FontFamily.Families){ // 处理代码} ...