好記性不如爛筆頭 ——東西太多,腦子永遠(yuǎn)不夠用
問題
用 C 語言寫個(gè)程序,運(yùn)行時(shí),cpu占用率一直保持50%
解決方案
一看題目好眼熟!《編程之美》!然而已經(jīng)記不清楚了,果然東西需要經(jīng)常用經(jīng)常積累,廢話不多說重來一遍。
第一步:cpu占用率計(jì)算方法
既然想要讓cpu占有率一直保持一定數(shù)值,就想要弄明白,cpu占用率是如何得到的
在Linux下,CPU利用率分為用戶態(tài),系統(tǒng)態(tài)和空閑態(tài),分別表示CPU處于用戶態(tài)執(zhí)行的時(shí)間,系統(tǒng)內(nèi)核執(zhí)行的時(shí)間,和空閑系統(tǒng)進(jìn)程執(zhí)行的時(shí)間,三者之和就是CPU的總時(shí)間,當(dāng)沒有用戶進(jìn)程、系統(tǒng)進(jìn)程等需要執(zhí)行的時(shí)候,CPU就執(zhí)行系統(tǒng)缺省的空閑進(jìn)程。從平常的思維方式理解的話,CPU的利用率就是非空閑進(jìn)程占用時(shí)間的比例,即CPU執(zhí)行非空閑進(jìn)程的時(shí)間/ CPU總的執(zhí)行時(shí)間。
那么問題就很簡單了,我們只要保持讓cpu運(yùn)行50,休息50就可以保證cpu的利用保持在50%了(忽略其他程序的影響)。運(yùn)行到100%很簡單,無限循環(huán)執(zhí)行代碼,不過應(yīng)該會(huì)報(bào)錯(cuò)吧?先試試。
#include <stdlib.h>
int main(){
while(1){
for(int i = 0 ;i<100;i++);
}
return 0;
}
代碼執(zhí)行完畢,成功接近100%(話說死循環(huán)不報(bào)錯(cuò)的嗎?)

下面我們要做的就是控制好進(jìn)程閑置的時(shí)間,讓cpu的閑置時(shí)間等于非閑置時(shí)間,問題也就解決了。最笨的方法先填一個(gè)數(shù)字試試。
#include <unistd.h>
#include <stdlib.h>
int main(){
while(1){
for(int i = 0 ;i<100;i++){};
sleep(50);
}
return 0;
}
在mac下for循環(huán)后面需要加花括弧不然會(huì)報(bào)錯(cuò),不知道為什么之前的不報(bào)錯(cuò)。
結(jié)果是沒有反應(yīng)。cpu:0,執(zhí)行時(shí)間0。好吧好像太低估cpu能力了。還是科學(xué)一點(diǎn)的方案吧。用時(shí)鐘記錄運(yùn)行開始時(shí)間,并控制runtime和idle的時(shí)間比例就可以了。雖然時(shí)鐘會(huì)有一定的誤差,但是理論上是可以行的通的。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(){
int time_start;
int fulltime = 100;//總時(shí)間
int runtime = 50;//運(yùn)行時(shí)間
while(1){
time_start = clock();
while((clock()-time_start)<runtime){}
usleep(fulltime-runtime);
}
return 0;
}

從運(yùn)行結(jié)果中,可以看到并沒有達(dá)到50%,根據(jù)我的猜測有以下幾點(diǎn)影響:
1、系統(tǒng)中還有其他運(yùn)行程序,留給本程序的cpu肯定達(dá)不到100% 。從理論上來說本程序進(jìn)行的更頻繁,占用cpu也會(huì)更多,可以嘗試把時(shí)間改到1,結(jié)果應(yīng)該會(huì)更接近點(diǎn)
2、時(shí)鐘計(jì)算的誤差,無論是clock()還是usleep()都存在誤差。特別是睡眠的時(shí)鐘會(huì)設(shè)置一個(gè)緩沖區(qū)域,之前之后醒來都可以。
如果想要做的更準(zhǔn)確的話,應(yīng)該實(shí)時(shí)監(jiān)測cpu使用率,然后來控制程序運(yùn)行,不過應(yīng)該也做不到完全準(zhǔn)確,畢竟cpu使用率只是一個(gè)統(tǒng)計(jì)值。
關(guān)于sleep()函數(shù)的單位很頭疼,不同平臺(tái)好像有不同的參數(shù)單位,可以自己嘗試一下。
附上java代碼以及運(yùn)行結(jié)果
import java.lang.Thread;
import java.text.SimpleDateFormat;
public class cpu50 {
public static void main(String[] args) {
long time_start;
int fulltime = 100;
int runtime = 50;
while(true){
time_start = System.currentTimeMillis();
while((System.currentTimeMillis()-time_start)<runtime){}
try {
Thread.sleep(fulltime-runtime);
}catch (InterruptedException e) {
return;
}
}
}
}```
