前言

从开始学习编程之后,就渐渐痴迷于技术,平时遇到购书满减活动时就忍不住买一堆书。前两天闲着无聊,翻开了去年买的《编程之美》,目录里的“让 CPU 占用率听你指挥”吸引力我的眼球。这一年来捣鼓数据挖掘和机器学习,总会关注代码运行效率,偶尔会思考如何提高 CPU、GPU 的利用率。于是马上翻开了这一节。

让 CPU 利用率听你指挥

翻开后是一道编程题(3星,需要查阅一些资料,在60分钟内完成)

写一个程序,让用户来决定 Windows 任务管理器(Task Manager)的 CPU 占用率。程序设计的越精简越好,语言不限。例如,可实现下面三种情况:

  1. CPU 和占用率固定在50%,为一条直线
  2. CPU 的占用率为一条直线,具体占用率由命令行参数决定(参数范围 1~100)
  3. 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 “玩”起来的更多相关文章

  1. C#正则表达式引发的CPU跑高问题以及解决方法

    3月23日(周日)下午16:30左右,博客园主站负载均衡中的2台Web服务器CPU玩起了爬楼梯的游戏(见上图),一直爬到了接近100%.发现这个状况后,我们立即将这2台阿里云临时磁盘云服务器从负载均衡 ...

  2. 横跨十年CPU架构回顾

    http://cpu.zol.com.cn/209/2092791_all.html#p2092791 本文导航 第1页:K7架构 打开AMD崛起大门的钥匙 第2页:玩破解 K7时代便已经拥有 第3页 ...

  3. Acer4315笔记本CPU升级

    终于有时间升级一下不怎么用的旧笔记本Acer4315了.在计划升级前了解了一下,芯片组是GL960,支持可升级的CPU有: CM560 CM570 T1600 T1700 T2310 T2330 T2 ...

  4. STM32 串口功能 库函数 详解和DMA 串口高级运用(转载)

    数据传输时要从支持那些相关的标准?传输的速度?什么时候开始?什么时候结束?传输的内容?怎样防止通信出错?数据量大的时候怎么弄?硬件怎么连接出发,当然对于stm32还要熟悉库函数的功能 具起来rs232 ...

  5. Linux kernel parameter command line设置

    现在CPU2核以上比较普遍了,平时用linux上上网可能用不着双核甚至4核,大部分发行版内核都启用了CPU_HOTPLUG,到/sys/devices/system/cpu下可以看到文件夹cpu0.c ...

  6. 教你从头到尾利用DQN自动玩flappy bird(全程命令提示,GPU+CPU版)【转】

    转自:http://blog.csdn.net/v_JULY_v/article/details/52810219?locationNum=3&fps=1 目录(?)[-] 教你从头到尾利用D ...

  7. 玩转CPU运行曲线

    Leaf 是不是从来没有想过看看cpu运行曲线啊骚年?顶多也就仅仅是看看cpu利用率,吓自己一跳后感觉关闭几个不该打开的程序~ 然而问题来了,微软公司要让你绘制cpu运行曲线啊!!不仅是固定的直线,还 ...

  8. 深入理解 Linux Cgroup 系列(二):玩转 CPU

    原文链接:深入理解 Linux Cgroup 系列(二):玩转 CPU 上篇文章主要介绍了 cgroup 的一些基本概念,包括其在 CentOS 系统中的默认设置和控制工具,并以 CPU 为例阐述 c ...

  9. [转帖]海思大佬称华为CPU同频追平AMD 注水吹嘘玩文字游戏?

    海思大佬称华为CPU同频追平AMD 注水吹嘘玩文字游戏? https://t.cj.sina.com.cn/articles/view/6635931736/18b88485800100cz4h?fr ...

随机推荐

  1. H3C STP可选配置

  2. vue-learning:28 - component - 组件事件的修饰符`.native / .sync`,以及组件属性`model`

    组件事件的修饰符.native / .sync,以及组件属性model .native 原生事件修饰符 在一个组件中,如果我们为其绑定一个原生的点击事件@click,基本是无效的. 在vue中对组件绑 ...

  3. Spark MLlib 示例代码阅读

    阅读前提:有一定的机器学习基础, 本文重点面向的是应用,至于机器学习的相关复杂理论和优化理论,还是多多看论文,初学者推荐Ng的公开课 /* * Licensed to the Apache Softw ...

  4. 阿里云“网红&quot;运维工程师白金:做一个平凡的圆梦人

    他是阿里云的一位 P8 运维专家,却很有野心得给自己取花名“辟拾(P10)”:他没有华丽的履历,仅凭着 26 年的热爱与坚持,一步一个脚印踏出了属于自己的技术逆袭之路:他爱好清奇,练就了能在 20 秒 ...

  5. jQuery的使用及关于框架造型 专题

    Introduction 正如jQuery所宣称的一样,Write Less, Do More.很多时候我们喜欢用它来解决问题.但增加一个库必然意味着更大的网络负担,意味着更高的页面初始载入时间.并且 ...

  6. QString 转换为 char *

    一.QString 转换为 char * 将 QString 转 char *,需要用到 QByteArray 类,QByteArray 类的说明详见 Qt 帮助文档. 因为 char * 最后都有一 ...

  7. 面试必问之 ConcurrentHashMap 线程安全的具体实现方式

    作者:炸鸡可乐 原文出处:www.pzblog.cn 一.摘要 在之前的集合文章中,我们了解到 HashMap 在多线程环境下操作可能会导致程序死循环的线上故障! 既然在多线程环境下不能使用 Hash ...

  8. DEVOPS技术实践_20:串联多个job执行

    在jenkins可能会有战役中场景,就是在一个job执行完之后,把这个执行结果作为另一个job的执行条件 比如A执行完,如果A执行成功,则执行B,如果失败则执行C 1 前期准备 A任务 import ...

  9. Spring Boot (5) 整合 RabbitMQ

    一.前言 RabbitMQ是实现了AMQP(高级消息队列协议)的开源消息中间件,RabbitMQ服务器是用Erlang(面向并发的编程语言)编写的. RabbitMQ官网下载地址:https://ww ...

  10. c++简单实现二叉树

    专业术语: 节点 父节点 根节点 子孙 堂兄弟 深度: 从根节点到最底层节点的层数称为深度 叶子节点: 没有子节点的节点称为叶子节点 非终端节点: 实际就是非叶子节点 度: 子节点的个数称为度 树的分 ...