真实 Linux 早就不做【固定时间片轮转】了:CFS 只记账、不预设时间片,永远挑累计跑得最少的那个;6.6 之后换成 EEVDF,在记账之上加了截止时间。权重(nice)改的是记账斜率。
4.10 讲完了那对矛盾,这一节看看真系统怎么在两者之间做选择——它用的方法是【不预设时间片,只记账】。
一、从【预设时间片】到【只记账】
固定时间片的问题:你要先猜一个数。猜小了切换多,猜大了响应慢,而负载是变的,猜不准。 CFS 的办法:不预设。给每个进程记一个【已经跑了多少】的账(虚拟运行时间),永远挑账上最少的那个。 效果:可跑进程少时,每个进程能连着跑很久(自动变大时间片);可跑进程多时,每个只跑一点点(自动变小)。时间片成了结果,不再是参数。 这就是【按需分配】取代【按配置分配】——少了一个要人猜的数。
二、权重怎么起作用
每个进程有一个权重(由 nice 值换算),跑一拍只按 1/权重 记账。
权重大的,账涨得慢,所以下一次还是它账最少,还能接着跑——它拿到的 CPU 时间就多。
实测:权重 1 比 1 时各拿一半;2 比 1 时拿到 67 比 33;4 比 1 时拿到 80 比 20。
注意这是【按比例分账】,不是【高优先级先跑完】——低权重的进程不会被饿死,只是拿得少。
三、EEVDF 加了什么
CFS 只有一个目标:公平。它不管【谁等得急】。 EEVDF 在记账之上加了【截止时间】:每个进程有一个【希望什么时候被服务到】的时间,调度时既看账、也看这个截止时间。 好处:延迟敏感的任务(比如音视频、交互)能被更早服务,而不必靠调高 nice 去抢。 这仍然是在吞吐与延迟之间取平衡,只是把权衡从【一个时间片参数】变成了【两个维度一起算】。
四、你在哪能看到这些
/proc/stat:整机 CPU 时间怎么花的(user/nice/system/idle/iowait…)。
/proc/<pid>/schedstat:这个进程跑了多久、等了多久、被迁移过几次。
/proc/<pid>/sched:一大段,里面有 vruntime、权重、迁移次数。
ps -o ni,pri,cmd:nice 值与显示优先级。
这些文件都不占磁盘、读一次生成一次——它们是内核给你留的窗口。
五、动手 Demo:现实中的系统——真正的调度器在算什么
这一节不跑模拟,只把真系统的三个概念摆清楚:记账(vruntime)、权重(nice)、截止时间(EEVDF),再告诉你它们各在哪个文件里能看到。
# 真系统上这四个地方能看到调度器的账本
# 1. 整机时间怎么花的
cat /proc/stat | head -1
# 2. 某个进程跑了多久、等了多久、迁移过几次
cat /proc/<pid>/schedstat
# 3. 它的 vruntime、权重、优先级
grep -E "se.vruntime|prio|nr_switches" /proc/<pid>/sched
# 4. nice 值与显示优先级
ps -o pid,ni,pri,comm -p <pid>
实跑输出:
--------------------------------------------------------------------
现实中的系统——真正的调度器在算什么
--------------------------------------------------------------------
① 从【时间片轮转】到【按权重分账】
阶段 代表 它按什么挑人
-------------------------------------------------------
早期 简单轮转 排到谁是谁
2.6 之后 CFS 谁累计跑得少挑谁(vruntime)
6.6 之后 EEVDF 在 CFS 基础上加【截止时间】
**CFS 的想法很朴素**:不预设时间片,**只记账**——
每个进程记一个【已经跑了多久】,永远挑账上最少的那个。
**权重(nice 值)影响的是记账的斜率**:权重大的,跑一拍只记一点点,
**所以同样的时间里它能多跑几拍。**
② 你在哪能看到它
想看什么 看哪儿 长什么样
----------------------------------------------------------------------
谁来调度 /sys/block 不相关;看 `chrt -p` 调度策略与优先级
分了多少时间 /proc/<pid>/schedstat 三个数列
整体忙不忙 /proc/stat cpu 行一串数字
优先级 ps -o ni,pri,cmd nice 与 pri 两列
**这些数字不是给好奇的人看的**:调优、查【为什么这个进程慢】、
判断【是不是被别的进程抢了 CPU】,全靠它们。
CFS 最有价值的一句话:时间片不是参数,是结果。可跑进程少时自动变大,多时自动变小——不用再猜一个数。 权重按比例分账,不按先后排序。这条区别很重要:调高 nice 不会让 A 更快,只会让 B 更慢(抢的时候多拿一点)。 EEVDF 是 6.6 之后的新默认,它把【公平】与【等得急】两个目标一起算。你若在内核 6.6 以上的系统上,默认已经是它了。
📋 一条命令看清整机在干什么:vmstat 1——r 是可跑进程数、cs 是切换次数、us/sy/id/wa 是时间去向。r 长期大于核数,说明 CPU 不够;wa 高说明在等 IO。
30 秒实验
cat /proc/stat | head -1,隔 5 秒再读一次,把两行相减算出这 5 秒里 idle 占多少。ps -eo ni,pri,comm --sort=-ni | head——看谁的 nice 最高(最谦让)。cat /proc/<pid>/sched | head -20,找到nr_switches与se.vruntime两行。
常见误区
- 【Linux 用固定时间片轮转】。那是教材里的简化模型。真系统用记账(CFS/EEVDF),时间片是算出来的。
- 【nice 调高就会更快】。它只影响抢 CPU 时的分配比例。如果 CPU 本来就闲,调 nice 一点用都没有。
- 【CFS 保证公平,所以不会饿死】。基本对,但【公平】是相对的;极端权重差下,低权重进程拿到的份额可以很小。
自测三问(点开对答案)
1. CFS 与固定时间片轮转最大的区别是什么? —— **不预设时间片,只记账**:给每个进程记虚拟运行时间,永远挑最少的。**时间片成了结果,不再是需要人猜的参数。** 2. 权重(nice)怎么起作用? —— 跑一拍按 `1/权重` 记账,权重大的账涨得慢,**所以能多跑**。结果是**按比例分账**,不是按优先顺序排。 3. EEVDF 在 CFS 之上加了什么? —— 加了**截止时间**:既看账、也看谁等得急。**延迟敏感的任务能被更早服务。**- ☐ 4.12 存在多个逻辑 CPU 时的调度
相关笔记
- 吞吐量与延迟 — 那对矛盾的现实解法
- 存在多个逻辑 CPU 时的调度 — 下一步是多个核
- 变更优先级 — nice 的实测
- 🐧 Linux是怎样工作的 · 索引