把 CPU “玩”起来
前言
从开始学习编程之后,就渐渐痴迷于技术,平时遇到购书满减活动时就忍不住买一堆书。前两天闲着无聊,翻开了去年买的《编程之美》,目录里的“让 CPU 占用率听你指挥”吸引力我的眼球。这一年来捣鼓数据挖掘和机器学习,总会关注代码运行效率,偶尔会思考如何提高 CPU、GPU 的利用率。于是马上翻开了这一节。
让 CPU 利用率听你指挥
翻开后是一道编程题(3星,需要查阅一些资料,在60分钟内完成)
写一个程序,让用户来决定 Windows 任务管理器(Task Manager)的 CPU 占用率。程序设计的越精简越好,语言不限。例如,可实现下面三种情况:
- CPU 和占用率固定在50%,为一条直线
- CPU 的占用率为一条直线,具体占用率由命令行参数决定(参数范围 1~100)
- CPU 的占用率状态是一条正弦曲线
怎么实现呢
稍微想了想,如果想让 CPU 跑满,写一个死循环就好了,让 CPU 一直处于运行状态,那 50% 的利用率要怎么实现呢?一半时间运行一半时间休息,emmmmm。。休息。。突然想到了多线程里常用到的 sleep。接着往下看,确实是使用 sleep。
那就写写代码吧
while True:
for i in range(7200000):
pass
time.sleep(0.01)
这里稍微解释下为什么是 7200000,以及为什么睡眠 0.01s(10ms)。
笔记本的 CPU 是 1.8Ghz,每秒运行次数大概为 1.8 * 10^9 次,假设 CPU 每个时钟周期可以执行两条代码,然后对于一段 for 循环代码,转换成汇编如下
next:
mov eax, dword ptr[i] ; i放入寄存器
add eax, 1 ; 寄存器+1
mov dword ptr [i], eax ; 寄存器赋回i
cmp eax, dword ptr [i] ; 比较i和n
j1 next ; i小于n时重复循环
即5条代码,所以,1S 内循环次数为 1.8 * 10^9 * 2 / 5 = 720000000。而睡眠 10ms 是因为接近 Windows 的调度时间片。
运行了一下,只是稳定在 30% 左右,暂时先不调整循环次数,接着往后看。
可以看出来,这样设置利用率很麻烦,那有没有什么方法可以快点设置呢?
重新看看上面这段代码, 7200000 次循环花费的时间大约为 10ms,那意思就是 CPU 运行 10ms 然后再休息 10ms,再运行 10ms 再休息 10ms,接着运行 10ms 然后再休息 10ms ······ 想必肯定看出来什么了吧,我们只需要设置 CPU 运行多少时间就好了!于是可以写出下面代码
busyTime = 0.01
while True:
startTime = time.clock()
while((time.clock() - startTime) <= busyTime):
pass
time.sleep(busyTime)
运行一下,跟刚刚差不太多,稳定在 30% 左右
正弦函数
这时候,我们也可以很容易就写出跑成正弦函数图像的代码了,不断改变运行与空闲的时间比就好了。
import time
import mathimport affinity
from multiprocessing import Process, cpu_count def exec_fun():
SAMPLING_COUNT = 200 # 抽样点数量
PI = math.pi # pi
TOTAL_AMPLITUDE = 300 # 每个抽样点对应时间片
busySpan = [] amplitude = TOTAL_AMPLITUDE / 2
radianIncrement = 2.0 / SAMPLING_COUNT
radian = 0.0
for i in range(SAMPLING_COUNT):
busySpan.append((amplitude + math.sin(PI * radian) * amplitude) / 1000.0)
radian += radianIncrement
# print(busySpan[i], TOTAL_AMPLITUDE - busySpan[i]) j = 0
while True:
startTime = time.clock()
# print(startTime)
while ((time.clock() - startTime) <= busySpan[j]):
pass
# print('sleep')
time.sleep(0.3 - busySpan[j])
j = (j + 1) % SAMPLING_COUNT exec_fun()
运行一下。emmmmmmmmmmmm。。。。等一下,不对啊,怎么不是正弦函数形状呢?

这跟说好的好像不太一样啊。是不是因为用的是 python,跑的本来就慢的原因?那试试 C++ 吧
#include<stdlib.h>
#include<Windows.h>
#include<math.h> const int SAMPLING_COUNT = ;
const double PI = 3.1415926535;
const int TOTAL_AMPLITUDE = ; int main()
{
DWORD busySpan[SAMPLING_COUNT];
int amplitude = TOTAL_AMPLITUDE / ;
double radian = 0.0;
double radianIncrement = 2.0 / (double)SAMPLING_COUNT;
for (int i = ; i < SAMPLING_COUNT; i++) {
busySpan[i] = (DWORD)(amplitude + sin(radian * PI) * amplitude);
radian += radianIncrement;
printf("%d\t%d\n", busySpan[i], TOTAL_AMPLITUDE - busySpan[i]);
}
DWORD startTime = ;
for (int j = ;; j = (j + ) % SAMPLING_COUNT) {
startTime = GetTickCount();
while ((GetTickCount() - startTime) <= busySpan[j]);
Sleep(TOTAL_AMPLITUDE - busySpan[j]);
}
return ;
}
再运行一下,它怎么还是这样???

于是乎捣鼓了 2 个小时。。。
……
……
……
后来仔细想了想,CPU 是 4 核 8 处理器的,不会是任务分摊到了几个处理器上了吧?于是查了查如何把当前进程放在一个处理器上执行。
if __name__ == "__main__":
p = Process(target=exec_fun)
p.start()
pid = p.pid
print(affinity.get_process_affinity_mask(pid))
affinity.set_process_affinity_mask(pid, )
运行一下,好的,它成了!!!

顺便解决下上面C++的代码,在 main() 函数最开始加入下面代码
SetThreadAffinityMask(GetCurrentThread(), );
小节
好久没有这样子捣鼓过东西了,想想上次做操作系统课设的时候,要获取系统的信息,当时只是为了完成任务就没有去深究一些东西,这次捣鼓了 CPU 的利用率控制之后,对进程、CPU 以及 python 的多线程等知识又多了一点了解。感觉技术还是需要沉下心来才能学得好。
把 CPU “玩”起来的更多相关文章
- C#正则表达式引发的CPU跑高问题以及解决方法
3月23日(周日)下午16:30左右,博客园主站负载均衡中的2台Web服务器CPU玩起了爬楼梯的游戏(见上图),一直爬到了接近100%.发现这个状况后,我们立即将这2台阿里云临时磁盘云服务器从负载均衡 ...
- 横跨十年CPU架构回顾
http://cpu.zol.com.cn/209/2092791_all.html#p2092791 本文导航 第1页:K7架构 打开AMD崛起大门的钥匙 第2页:玩破解 K7时代便已经拥有 第3页 ...
- Acer4315笔记本CPU升级
终于有时间升级一下不怎么用的旧笔记本Acer4315了.在计划升级前了解了一下,芯片组是GL960,支持可升级的CPU有: CM560 CM570 T1600 T1700 T2310 T2330 T2 ...
- STM32 串口功能 库函数 详解和DMA 串口高级运用(转载)
数据传输时要从支持那些相关的标准?传输的速度?什么时候开始?什么时候结束?传输的内容?怎样防止通信出错?数据量大的时候怎么弄?硬件怎么连接出发,当然对于stm32还要熟悉库函数的功能 具起来rs232 ...
- Linux kernel parameter command line设置
现在CPU2核以上比较普遍了,平时用linux上上网可能用不着双核甚至4核,大部分发行版内核都启用了CPU_HOTPLUG,到/sys/devices/system/cpu下可以看到文件夹cpu0.c ...
- 教你从头到尾利用DQN自动玩flappy bird(全程命令提示,GPU+CPU版)【转】
转自:http://blog.csdn.net/v_JULY_v/article/details/52810219?locationNum=3&fps=1 目录(?)[-] 教你从头到尾利用D ...
- 玩转CPU运行曲线
Leaf 是不是从来没有想过看看cpu运行曲线啊骚年?顶多也就仅仅是看看cpu利用率,吓自己一跳后感觉关闭几个不该打开的程序~ 然而问题来了,微软公司要让你绘制cpu运行曲线啊!!不仅是固定的直线,还 ...
- 深入理解 Linux Cgroup 系列(二):玩转 CPU
原文链接:深入理解 Linux Cgroup 系列(二):玩转 CPU 上篇文章主要介绍了 cgroup 的一些基本概念,包括其在 CentOS 系统中的默认设置和控制工具,并以 CPU 为例阐述 c ...
- [转帖]海思大佬称华为CPU同频追平AMD 注水吹嘘玩文字游戏?
海思大佬称华为CPU同频追平AMD 注水吹嘘玩文字游戏? https://t.cj.sina.com.cn/articles/view/6635931736/18b88485800100cz4h?fr ...
随机推荐
- vue-learning:21 - js - mixins
mixins 混入是一种对重复代码的组织方式,可以在多个组件间复用代码. 如果在项目中,在多个组件间有一段逻辑代码是共同的.那常见的处理方式是: 每个组件都复制粘贴代码(显然这是最不好方式) 将以共同 ...
- linux查看文件内容跳到文件底部和回到文件顶部的快捷键
有时候需要查看一些日志文件,然后要从底部开始查看的话 可以按 shift+g 即可跳到文件底部 要返回文件顶部的时候 按 gg即可
- mac如何查看已连接wifi的密码
可以通道mac自带的“钥匙串访问”功能查看.选择需要查询的wifi名称,右击选择“将密码拷贝到剪贴板”,输入管理员密码后,密码就拷贝好了. 找个地方粘贴即可看到密码
- 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)
[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...
- 洛谷$P2598\ [ZJOI2009]$狼和羊的故事 网络流
正解:网络流 解题报告: 传送门! 昂显然考虑最小割鸭$QwQ$,就考虑说每个土地要么属于羊要么属于狼,然后如果一条边上是栅栏一定是相邻两边所属不同. 所以考虑给所有羊向$S$连$inf$,所有狼向$ ...
- $Noip2018/Luogu5019/Luogu1969$ 铺设道路
$Luogu$ 去年$Noip$的时候我并没有做过原题,然后考场上也没有想出正解,就写了个优化了一点的暴力:树状数组+差分,然后就$A$了$ovo$. $Sol$ 只要$O(N)$扫一遍,只要当前值比 ...
- C#泛型(Generic)
一.什么是泛型 泛型(Generic)是C#语言2.0.通用语言运行时(CLR)2.0..NET Framework2.0推出来的新特性. 泛型为.NET框架引入类型参数(Type Parameter ...
- CAP理论的理解
CAP理论作为分布式系统的基础理论,它描述的是一个分布式系统在以下三个特性中: 一致性(Consistency) 可用性(Availability) 分区容错性(Partition tolerance ...
- 钱包开发经验分享:ETH篇
# 钱包开发经验分享:ETH篇 [TOC] ## 开发前的准备 > 工欲善其事,必先利其器 一路开发过来,积累了一些钱包的开发利器和网站,与大家分享一下.这些东西在这行开发过的人都知道,只是给行 ...
- 测开大佬告诉你:如何5分钟快速创建restful风格的API接口-使用django restframework框架
一.思考❓❔ 1.创建API接口难吗? 软件测试工程师: 只测过API接口, 从没创建过 应该需要掌握一门后端开发语言和后端开发框架吧!? 脑容量有限,想想就可怕 2.如何创建API接口呢? 使用Dj ...