没有进程可跑的时候,CPU 并没有【歇着】,它在跑空闲进程——一条等中断的指令。这么设计是为了让调度器永远有活可挑,省掉一堆【没活时怎么办】的特殊分支。
4.7 画完了状态机,这一节补一个容易被漏掉的状态:没人可跑的时候。它不在教材的状态机里,但在真实系统里一直存在。
一、没有可跑进程时,CPU 在干什么
它没有停。它执行一条【等中断】的指令(x86 上是 hlt,ARM 上是 wfi),CPU 进入低功耗状态,等下一个中断把它叫醒。
中断来了(定时器、网卡、磁盘),它就醒,看看有没有活儿,没有就继续等。
所以【空闲】不是【停止】,是【等】——而且这个【等】也在一个进程里。
二、为什么必须做成【一个进程】
因为调度器的主循环需要【永远有东西可挑】。
如果允许【就绪队列为空】,调度器就要写一堆特殊分支:空的时候怎么办、什么时候再看一眼、被谁叫醒。
把空闲做成一个进程(Linux 上是 0 号进程 swapper),主循环就永远能挑到一个——挑到它,就执行 hlt 等中断。
这是很典型的系统设计手法:把一个边界情况变成一个正常情况,代码就少一半。
三、两种说法的差别
【CPU 在跑 idle 进程】:从调度器角度,永远有活。好处是代码简单。
【CPU 闲着】:从人的角度,没干有用的事。好处是直观。
两种说法描述同一件事,只是站的位置不同。看 top 里的 id 那一列时,你在用后一种说法。
这件事有个实际后果:ps 里看到的进程数不包含 idle(它是内核线程,通常看不见),所以【进程数】与【谁在跑】不是一回事。
四、空闲不是浪费,是能力
一台机器的空闲率,代表它还有多少余量。空闲 0% 的机器不是健康的机器,是没余量的机器。 所以容量规划看的不是【峰值有多高】,是【峰值时还剩多少】——剩得少,下一次流量小高峰就会打满。 反过来,空闲率长期 90% 以上的机器,是在浪费钱——可以合并、可以缩容。
五、动手 Demo:空闲状态——没有进程可跑时,CPU 在干什么
放一个进程进去,让它跑 2 拍就等 30 拍,然后数一数时间线上有多少格是空的。 这些空格就是【idle 进程】在跑的时候。
ps = [Proc("A", 4, io_each=2, io_len=30)]
done, sw, tl, total = run(ps, quantum=4, ncpu=1, horizon=40)
idle = sum(1 for _t, names in tl if names[0] == "-")
print("观察", len(tl), "拍,空着", idle, "拍,占", idle / len(tl))
实跑输出:
--------------------------------------------------------------------
空闲状态——没有进程可跑时,CPU 在干什么
--------------------------------------------------------------------
① 一个进程,跑 2 拍就等 30 拍
总观察时间 33 拍
CPU 空着的时间 29 拍
空着占比 88%
**这时候 CPU 没有【歇着】——它在跑【空闲进程】。**
**Linux 上就是 0 号进程(swapper)的 idle 循环**:
执行一条【等中断】的指令,来中断就醒,看看有没有活儿,没有就继续等。
② 为什么要有【空闲进程】这个说法
说法 物理事实 为什么这么讲
------------------------------------------------------------
CPU 在跑 idle 执行等中断指令 调度器眼里永远有活可干
CPU 闲着 同样在等中断 从人看的角度更直观
**两种说法描述的是同一件事,只是站的位置不同。**
**调度器要保证【永远有东西可挑】——所以空闲也必须是个进程。**
**否则调度器就得写一堆【没有就绪进程时怎么办】的特殊分支。**
空着的那些拍占比很高——因为 30 拍的等待远长于 2 拍的计算。
这些拍在真机上就是 top 里的 id(idle 的百分比)。你在 top 上看到的 95% id,就是这张时间线上 95% 的空格。
【空闲】也要有人记账:不记账的话,top 里的百分比加起来就不是 100%。
记住这句:空闲 0% 不是健康,是没余量;空闲长期 90% 是浪费钱。
30 秒实验
top看id那一列,再对比vmstat 1的id——两个数应该接近。cat /proc/stat | head -1看idle字段的累计值,隔几秒再读一次,相减除以增量。ps -eLo pid,psr,stat,comm | grep -c " R"数一下有几个进程真在跑。
常见误区
- 【CPU 不用的时候是关掉的】。它在执行等中断的指令,随时能被叫醒。真关掉再启动要几毫秒,那就没法用了。
- 【空闲率高的机器一定有问题】。可能它本来就没什么活。要看的是【峰值时还剩多少】。
- 【idle 进程占 CPU】。它占的是【时间】,不占算力——
hlt期间 CPU 基本不耗电(相对而言)。
自测三问(点开对答案)
1. 没有可跑进程时,CPU 在做什么? —— 在跑空闲进程,执行等中断指令(`hlt`/`wfi`),进低功耗,等中断叫醒。 2. 为什么非要把空闲做成一个进程? —— 让调度器永远有东西可挑,**省掉【就绪队列为空怎么办】的一堆特殊分支**。这是把边界情况变成正常情况的典型手法。 3. 空闲率该怎么看才对? —— 看【峰值时还剩多少】,而不是看平均值。**0% 说明没余量,长期 90% 说明在浪费钱。**- ☐ 4.9 各种各样的状态转换
相关笔记
- 状态转换 — 合法的五条路
- 各种各样的状态转换 — 真实系统多出来的路
- 现实中的进程 — 在真机上看这些状态
- 🐧 Linux是怎样工作的 · 索引