《编程之美》-- 让CPU占用率听你指挥
来源:互联网 发布:网络推广课程 编辑:程序博客网 时间:2024/05/01 01:26
题目要求
写一个程序,让用户决定windows任务管理器(Task Manager)的CPU占用率。程序越精简越好,计算语言不限。例如,可以实现下面三种情况
1. CPU的占用率固定在50%,为一条直线;
2. CPU的占用率为一条直线,具体占用率由命令行参数决定(参数范围1~100);
3. CPU的占用率状态是一条正弦曲线
什么是CPU使用率
CPU执行应用的程序的时间和刷新周期总时间的比率,就是CPU使用率
操作CPU
要想CPU的使用率控制在50%(或者其他任意比例),我们首先要明白怎么让系统忙起来和闲起来。当一个程序运行的时候,系统就忙起来了。那怎么让它闲下来?很简单,当这些程序在等待用户输入,或者其他操作的时候,或者进入“休眠”的时候。
要操纵CPU的使用率曲线,就需要使CPU在一段时间内(根据任务管理器(Task Manager)的采样率)跑busy和idle两个不同的循环,从而通过不同的时间比率,来调节CPU的使用率
简单解法一
两个基本循环
busy : 我们使用一个for循环
for(int i = 0; i < n; ++i)
idle:我们使用Sleep函数
例如: 我们让程序停止10ms
Sleep(10)
这里重要的是知道n的值和需要程序休眠多少时间
什么是CPU频率?
CPU频率,就是CPU的时钟频率,简单说是CPU运算时的工作频率(1秒内发生的同步脉冲数)的简称
代码运行的CPU是P4 2.4GHZ 即 2.4 * 10^9
由于现代CPU每个时钟周期可以执行两条以上的代码,于是有
n =(2400000000 * 2)/ 5 = 960000000(循环秒)
和
Sleep(1000)
也就是说CPU1秒钟可以运行这个空循环960000000次
当然由于实际原因,会进行等比例缩放
所以取
n = 9600000
和
Sleep(10)
具体代码
因为本人的不是单核CPU,所以加了
SetThreadAffinityMask(GetCurrentThread(), 0x00000001);
目的是使这段代码运行在一个CPU里
#include <iostream>#include <unistd.h>#include <windows.h>using namespace std;int main(){ SetThreadAffinityMask(GetCurrentThread(), 0x00000001); for(;;) // while(1) { for(int i = 0; i < 9600000; i++) ; Sleep(10); // 本人电脑上这里要设置成Sleep(20)才能大致趋于50% } return 0;}
图
上图具体如下
使用GetTickCount()和Sleep()
#include <windows.h>#include <stdio.h>#include <stdlib.h>int main(){ SetThreadAffinityMask(GetCurrentThread(), 0x00000001); int busyTime = 50; int idleTime = busyTime; for(;;) // while(1) { int startTime = GetTickCount(); while((GetTickCount() - startTime) < busyTime) ; Sleep(idleTime); } return 0;}
在上面两种代码中都是假设目前没有其他程序运行,但实际上,我们往往会有很多进程,他们占用了或多或少的CPU,所以上面图中没有出现一条直线
能动态适应的解法
目前还不会C++的写法(可能会有某个API来获取当前的CPU使用率?performanceCounter?不过好像很麻烦),书上给出了C#的自适应解法,这里照搬下来
static void MakeUsage(float level){ PerformanceCounter p = new PerformanceCounter("Processor", "%Processor Time", "__Total"); while(true) { if(p.NextValue() > level) { System.Threading.Thread.Sleep(10); } }}
正弦曲线
分析
在系统中,CPU不可能真的画出正弦函数,而是有一个个时间点构成的连线,因此我在在正弦函数的一个周期中选择了200个坐标点,用于构成正弦函数图。
在正弦函数的选择上,我使用了最简单的
y=sin(x)
根据数据公式可以简单的知道:
1.周期
T = 2 * PI
2.点与点之间的时间间隔
t = T / 200 // T为周期,200为点的总数
3.busy和idle的时间
busy : busyTime[i] = sin(t * i)
idle:1 - busyTime[i]
// i 表示第几个点
因此得出了下面的代码
#include <windows.h>#include <iostream>#include <math.h>const int SAMPLING_COUNT = 200; // 抽样点数量 const double PI = 3.1415926535; // pi值const int TOTAL_AMPLITUDE = 300; // 每个抽样点对应的时间片int main(){ SetThreadAffinityMask(GetCurrentThread(), 0x00000001); double busyTime[SAMPLING_COUNT]; double radian = 0.0; double radianIncrement = 2 * PI / SAMPLING_COUNT; for(int i = 0; i < SAMPLING_COUNT; i++) { busyTime[i] = sin(radianIncrement * i); radian += radianIncrement; } for(int j = 0; ; j = (j + 1) % SAMPLING_COUNT) { int startTime = GetTickCount(); while((int)(GetTickCount() - startTime) < busyTime[j]) ; Sleep(1 - busyTime[j]); } return 0;}
图的效果不是很好,因此把代码改为如下
#include <windows.h>#include <iostream>#include <math.h>const int SAMPLING_COUNT = 200; // 抽样点数量 const double PI = 3.1415926535; // pi值const int TOTAL_AMPLITUDE = 300; // 每个抽样点对应的时间片int main(){ SetThreadAffinityMask(GetCurrentThread(), 0x00000001); double busyTime[SAMPLING_COUNT]; double radian = 0.0; double radianIncrement = 2 * PI / SAMPLING_COUNT; int amplitude = TOTAL_AMPLITUDE / 2; for(int i = 0; i < SAMPLING_COUNT; i++) { busyTime[i] = amplitude + sin(radianIncrement * i) * amplitude; radian += radianIncrement; } for(int j = 0; ; j = (j + 1) % SAMPLING_COUNT) { int startTime = GetTickCount(); while((int)(GetTickCount() - startTime) < busyTime[j]) ; Sleep(TOTAL_AMPLITUDE - busyTime[j]); } return 0;}
看起来好多了
至此,上面的题已经完成了
拓展
画个三角形图案
代码如下:
#include <windows.h>#include <iostream>#include <math.h>int main(){ SetThreadAffinityMask(GetCurrentThread(), 0x00000001); int SAMPLING_COUNT = 200; double TOTAL_AMPLITUDE = 200; double busyTime[SAMPLING_COUNT]; for(int i = 0; i < SAMPLING_COUNT; i++) { busyTime[i] = SAMPLING_COUNT / TOTAL_AMPLITUDE * i; } for(int j = 0; ; j = (j + 1) % SAMPLING_COUNT) { int startTime = GetTickCount(); while((int)(GetTickCount() - startTime) < busyTime[j]) ; Sleep(TOTAL_AMPLITUDE - busyTime[j]); } return 0;}
- 编程之美 之 让CPU占用率听你指挥
- 编程之美 - 让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 编程之美读书笔记-让CPU占用率听你指挥
- 《编程之美》-- 让CPU占用率听你指挥
- 编程之美:让CPU占用率曲线听你指挥
- 读书笔记之编程之美 - 1.1 让CPU占用率曲线听你指挥
- 编程之美1.1让CPU占用率曲线听你指挥之解法一细节
- 《编程之美》之读书笔记 1.1让CPU占用率曲线听你指挥
- 《编程之美》“让CPU占用率听你指挥”学习笔记
- 编程之美读书笔记_1.1_让CPU占用率曲线听你指挥
- 大学感悟【八】
- xutils
- eclipse Mac安装了tomcat7.0,启动后在window-> preferences选项中找不到tomcat项
- TODO:字节的那点事Go篇
- Android点击展示/收起更多详情+动画效果 Value
- 《编程之美》-- 让CPU占用率听你指挥
- IO多路转接
- 第9章-数据融合技术
- 如何禁止qq等程序运行
- 关于List的contains方法问题
- 17 :多台物理机间的容器连接
- Android studio集成阿里百川HotFix
- App Widget深入+Android Studio 真机断点调试注意事项
- intellij idea怎么退出断点? F9. intellij idea的debug模式的f9 = Eclipse的debug模式的f8一样