Linux下CPU时间片,CPU使用率分析,while和sleep分析

50 篇文章 3 订阅

一、时间片
简单来说就是CPU分配给各个程序的时间,使各个程序从表面上看是同时进行的,而不会造成CPU资源浪费。在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。但是在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。

二、Task调度
时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法是时间片调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU 当即进行切换。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。

时间片轮转调度中唯一有趣的一点是时间片的时长。从一个进程切换到另一个进程是需要一定时间的–保存和装入寄存器值及内存映像,更新各种表格和队列 等。假如进程切换(process switch) - 有时称为上下文切换(context switch),需要5毫秒,再假设时间片设为20毫秒,则在做完20毫秒有用的工作之后,CPU将花费5毫秒来进行进程切换。CPU时间的20%被浪费 在了管理开销上。

为了提高CPU效率,我们可以将时间片设为500毫秒。这时浪费的时间只有1%。但考虑在一个分时系统中,如果有十个交互用户几乎同时按下回车键,将 发生什么情况?假设所有其他进程都用足它们的时间片的话,最后一个不幸的进程不得不等待5秒钟才获得运行机会。多数用户无法忍受一条简短命令要5秒钟才能 做出响应。同样的问题在一台支持多道程序的个人计算机上也会发生。
从这我们可以看出,时间片设得太短会导致过多的进程切换,降低了CPU效率;而设得太长又可能引起对短的交互请求的响应变差。将时间片设为100毫秒通常是一个比较合理的折衷。
在这里插入图片描述
cpu执行了一个任务后,如果该任务还没有结束,那么又会重新放回Task Queue再度轮回。

实际上Task指的是线程,所以,一个进程开启多个线程会使CPU花更多的时间在该进程上面,但是开启太多的线程也是徒劳的。比如4核CPU,进程开启了8个线程,那么CPU能同时处理4个Task,其余4个还是在队列里面等待,即便如此,多余的4个线程还是有作用的,它使该进程抢占了CPU更多的时间片。

三、CPU占用率
使用 top 命令查看系统CPU使用率,主要看标红的地方,我的虚拟机为单核CPU。
在这里插入图片描述
数据3秒一刷新,看个大概就行。
total 就是总的任务数。
running 表示在Task Queue中的任务数。
sleeping 为阻塞的任务,比如调用了sleep, epoll_wait, select, accept 等带有阻塞属性的方法;sleeping 任务需要等到阻塞结束了才会放回到Task Queue

us 表示用户进程占用的比例,sy 表示系统进程占用的比例。

CPU的使用率可以理解为每个时间片被充分利用的综合程度。假设时间片为100ms,那么在1s之内会有10个时间片被分配到不同线程(假设不考虑上下文切换的时间),如果有8个线程执行了100ms还没结束,有2个线程执行了10ms就结束了,那么CPU使用率大致为 (8*100 + 2 * 20)/ 1000 = 84%
再比如4个50ms,6个60ms,那么使用率为 (4*50 + 6*60)/ 1000 = 56%

再看下面几个程序,本机上其他程序消耗CPU几乎为0.
1、CPU瞬间100%
因为当前进程的每个时间片都被充分利用了,并且每次又重新回到队列。

while(true){
    
};

2、CPU占用率0%
sleep调用将会使当前进程处于未就绪状态,也就不在Task Queue里面,直到睡眠时间到,将会放回到队列尾部,可能的表现就是:执行5ms,睡眠1s。。。这样一来它几乎没怎么占用CPU。

while(true){
    sleep(1);
};

3、CPU占用率0%
原理和2是一样的。

while(true){
    usleep(1000); // 1ms
};

4、CPU瞬间100%
sleep(0) 并没有发起sleep调用。

while(true){
    sleep(0);
};

5、CPU占用率us = 8%,但是 sy = 65%
因为 file_get_contents 发起了系统调用。

while(true){
    file_get_contents('test.php');
};

6、关于任务切换

$start = microtime(true);

sleep(1);

$end = microtime(true);

echo $end - $start;
echo PHP_EOL;

打印:1.000205039978
时间并不是1s,说明从休眠到被执行这之间也需要花费一定的时间。大致执行过程如下:
1、进程A获取到时间片开始执行 $start = microtime(true);
2、A发起sleep调用,结束A的时间片,并将A任务放入sleeping队列。
3、CPU继续执行Task Queue
4、大约1s之后,A处于就绪状态并投入到 Task Queue 尾部。
5、排在A之前的任务都执行了一遍之后轮到A获得时间片,执行 $end = microtime(true); 。。。。

所以说 sleep(1) 只是休眠时间,直到再次被执行的时间肯定不止1s,随着running task 的长度增大而增大。

并且由以上分析可知,在写网络服务的时候,尽量调用 epoll_wait 或者 select / poll 的阻塞返回模式;如果不得不使用 while 的话(比如消费进程),那么一定要加上 sleep 或者 usleep,这样将大大降低CPU使用率。

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值