CFS通过虚拟运行时间(vruntime)实现按权重的公平调度,公式为vruntime=实际运行时间×1024÷进程权重,权重由nice值映射(nice=0对应1024,nice=-20最高88761,nice=19最低15),高优先级进程vruntime增长慢、更易被选中;所有进程按vruntime组织成红黑树,始终选择最左节点(最小vruntime)运行,支持O(log n)高效调度,并结合目标延迟与最小粒度保障响应性与效率。

CFS不是靠“轮流分时间片”来调度的,而是用一套动态归一化的虚拟时间系统,让每个进程按权重“匀速追赶”,最终实现长期意义上的CPU时间公平分配。
vruntime:决定谁先跑的核心指标
每个进程维护一个 vruntime(虚拟运行时间),单位是纳秒。它不等于真实运行时间,而是经过权重缩放后的“公平时钟”。公式为:
vruntime = 实际运行时间 × 1024 ÷ 进程权重
权重由nice值决定:nice=0对应权重1024;nice越小(如-20),权重越大(最高88761);nice越大(如19),权重越小(最低15)。因此:
- 高优先级进程(nice低、权重高)——vruntime增长慢,更容易保持最小值,被频繁选中
- 低优先级进程(nice高、权重小)——vruntime增长快,但不会无限累积,仍能获得保障性执行机会
- 所有可运行进程的vruntime被持续更新,调度器永远挑当前最小的那个
红黑树:高效查找最小vruntime的容器
CFS不用链表遍历,也不用数组轮询,而是把所有可运行进程按vruntime值组织成一棵红黑树。这带来两个关键优势:
- 最左节点(leftmost)天然对应vruntime最小的进程,O(1)即可定位下一个要运行的任务
- 插入、删除、更新节点都控制在O(log n)复杂度,即便上千进程也能快速响应
- 树本身不保存“等待队列顺序”,只表达“谁欠得最少”,彻底摆脱传统调度器的时间片包袱
调度周期与最小粒度:平衡响应与开销
CFS设定了两个关键参数来约束调度行为:
- 目标延迟(target latency):默认约6ms,表示系统希望所有可运行进程在该窗口内至少轮到一次
- 最小调度粒度(min granularity):默认约0.75ms,防止进程太多时时间片过短、上下文切换爆炸
当进程数增加,单个进程分到的时间片会自动缩小,但不会低于最小粒度;超出部分会被累积到vruntime里,留待后续补偿——这保证了交互进程的响应性,也避免了CPU密集型任务被过度打断。
权重归一化与组调度:从进程到任务组的延伸
原始CFS按单个进程调度,但现代Linux支持任务组(task group),比如按用户、容器或cgroup划分资源配额。这时:
- 每个组有自己的cfs_rq和vruntime,组间按配置权重分配CPU总份额
- 组内进程再按各自权重二次分配,形成两级公平:组间公平 + 组内公平
- min_vruntime被全局跟踪,新唤醒或新创建的进程会被“摆正”到接近当前队列水平的位置,防止插队式抢占


















