zoukankan      html  css  js  c++  java
  • 第1章 游戏之乐——让CPU占用率曲线听你指挥

    让CPU占用率曲线听你指挥

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

    1. CPU的占用率固定在50%,为一条直线;
    2. CPU的占用率为一条直线,但是具体占用率由命令行参数决定(参数范围1~100);
    3. CPU的占用率状态是一个正弦曲线。

    【解法一】 简单的解法

      一个空的for循环for(int i=0;i<n;i++); 写成汇编代码后进行分析:

    loop:
    mov dx i  ;将i置入dx寄存器
    inc   dx    ;将dx从寄存器加1
    mov i  dx ;将dx中的值赋回i
    cmp i  n   ;比较i和n
    jl    loop  ; i小于n时则重复循环

    需要执行5条代码,假设要运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)。现在CPU每个时钟周期可以执行两条以上的代码,那么我们就取平均值两条,于是让(2660000000*2)/5=1064000000(循环/秒),如果让CPU工作1秒钟,然后休息1秒钟,波形很可能就是锯齿状的——先达到一个峰值(>50%),然后跌到一个很低的占用率。

    于是尝试降两个数量级。用10ms是因为它不大不小,比较接近Windows的调度时间片。如果太小会造成线程频繁被唤醒和挂起,无形中增加了内核时间的不确定性影响。最后我们得到如下代码:

    package chapter1youxizhile;
    /**
     * 【解法一】简单的方法
     * 运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)
     * @author DELL
     *
     */
    public class ControlCPU1 {
    
        public static void main(String[] args) {
            for( ; ; ){
                for(int i=0;i<10640000;i++);  //运行10ms
                try {
                    Thread.sleep(10);  //休眠10ms
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
        }
    
    }

      在不断调整10640000后,我们就可以在一台指定的机器上获得一条大致稳定的50%CPU占用率直线。

    【解法二】使用System.currentTimeMillis()和Thread.sleep()

    package chapter1youxizhile;
    /**
     * 【解法二】使用System.currentTimeMillis()和Thread.sleep()
     * 运行的CPU是2.66Ghz(2.66*10^9个时钟周期每秒)
     * @author DELL
     *
     */
    public class CopyOfControlCPU2 {
        
        public static void main(String[] args) {
            int busyTime = 10;  //繁忙时间10ms
            int idleTime = busyTime;  //空闲时间
            while(true){
                long startTime = System.currentTimeMillis(); //获取系统运行时间
                while(System.currentTimeMillis()-startTime<= busyTime) ;
                try {
                    Thread.sleep(idleTime);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
        }
    
    }

     效果如下:

      这两种解法都是假设目前系统上只有当前程序在运行,但实际上,操作系统中有很多程序会同时执行各种各样的任务,如果此刻其他进程使用了10%的CPU,那么我们的程序应该只能使用40%的CPU,这样才能达到50%的效果。

      怎么做呢?这就需要用到另个工具的帮忙——Perform.exe。如下图所示:

      我们可以写程序来查询Perform的值,Mircrosoft .Net Framework提供了PerformanceCounter这一对象,可以方便地得到当前各种性能的数据,包括CPU的使用率。例如下面这个程序:

     【解法三】能动态适应的解法

    //C# code
    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使用率的参数。这个程序可以解答前面提到的问题2。

    【解法四】正弦曲线

    package chapter1youxizhile;
    /**
     * 【解法四】正弦曲线
     * @author DELL
     *
     */
    public class CopyOfCopyOfControlCPU4 {
        static final double SPLIT = 0.01;  //2PI周期步长
        static final int COUNT = 200;  //取点个数
        static final double PI = 3.1415926;
        static final int INTERVAL = 300;  //空闲和繁忙的总时间
        public static void main(String[] args) {
            long busySpan[];  //CPU繁忙时间的数组
            long idleSpan[];  //CPU空闲时间的数组
            busySpan = new long[COUNT];
            idleSpan = new long[COUNT];
            int half = INTERVAL/2;
            double radian = 0.0;
            for(int i=0;i<COUNT;i++){
                busySpan[i] = (long) (half+(Math.sin(PI*radian)*half));
                idleSpan[i] = INTERVAL - busySpan[i];
                radian += SPLIT;
            }
            long startTime = 0;
            int j = 0;
            while(true){
                j = j%COUNT;  //实现周期循环
                startTime = System.currentTimeMillis();
                while((System.currentTimeMillis()-startTime)<=busySpan[j]) ;
                try {
                    Thread.sleep(idleSpan[j]);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                j++;
            }
        }
    
    }

    程序运行后任务管理器效果如下:

  • 相关阅读:
    vue自定义指令
    ZOJ Problem Set–2104 Let the Balloon Rise
    ZOJ Problem Set 3202 Secondprice Auction
    ZOJ Problem Set–1879 Jolly Jumpers
    ZOJ Problem Set–2405 Specialized FourDigit Numbers
    ZOJ Problem Set–1874 Primary Arithmetic
    ZOJ Problem Set–1970 All in All
    ZOJ Problem Set–1828 Fibonacci Numbers
    要怎么样调整状态呢
    ZOJ Problem Set–1951 Goldbach's Conjecture
  • 原文地址:https://www.cnblogs.com/gaopeng527/p/4598073.html
Copyright © 2011-2022 走看看