CFS的核心是按权重比例分配CPU时间,以vruntime为调度依据选择最小值进程运行,通过红黑树管理就绪队列,动态逼近理想多任务公平性,并支持多核负载均衡与组调度。

CFS 的核心不是“平均分配时间”,而是“按权重比例分配 CPU 时间”。它不靠固定时间片轮转,而是用虚拟运行时间(vruntime)作为调度依据,始终挑 vruntime 最小 的进程运行——就像马拉松里总让落后的选手先补跑一段,确保长期来看每人跑的“比例距离”一致。
虚拟运行时间(vruntime)是公平的标尺
每个可运行进程都维护一个 vruntime 值(单位:纳秒),它不是真实耗时,而是加权归一化后的时间量:
- 计算公式为:vruntime = 实际运行时间 × 1024 / 进程权重
- 权重由 nice 值决定:nice = −20 → 权重 = 820;nice = 0 → 权重 = 1024;nice = 19 → 权重 = 5
- 高优先级(低 nice)进程权重更大,vruntime 增长更慢,因此更容易被重复选中
- 低优先级进程 vruntime 增长快,但只要长时间未被调度,其 vruntime 就会相对变小,从而获得“补偿性”执行机会
红黑树组织就绪队列,O(log N) 高效选任务
CFS 不用传统队列数组,而把所有可运行进程按 vruntime 排序,存入一棵自平衡红黑树:
- 树最左端节点对应 vruntime 最小的进程,即下一个该运行的任务
- 新进程唤醒或迁移时,按其当前 vruntime 插入树中合适位置
- 上下文切换时只需取最左节点,插入/删除/查找均为 O(log N),支持成千上万进程高效调度
- 内核通过 rq->cfs.min_vruntime 跟踪队列中最小 vruntime,用于新进程放置和睡眠唤醒补偿
模拟理想多任务 CPU,动态逼近公平
CFS 的设计哲学是:在一台“理想的、无限并行”的 CPU 上,N 个进程应各得 1/N 的算力。现实单核只能串行,所以用 vruntime 模拟这种理想状态:
- 若系统有 2 个进程,权重分别为 1024 和 512,则长期来看,它们应分别获得约 66.7% 和 33.3% 的 CPU 时间
- vruntime 差值越小,说明实际分配越接近理论比例;差值拉大时,调度器自动倾向 vruntime 小者,实现动态追赶
- 即使某进程短暂霸占 CPU,它的 vruntime 会快速上升,很快被其他进程“反超”,避免饥饿
多核与负载均衡:per-CPU 红黑树 + 周期性迁移
现代 CFS 在多核系统中为每个 CPU 维护独立的 cfs_rq 和红黑树,同时引入跨核负载均衡机制:
- 当某 CPU 的可运行进程数显著高于邻居(如超过 25%),内核会在定时器中断中触发负载均衡
- 从过载 CPU 的红黑树中挑选 vruntime 较大的进程,迁移到空闲或轻载 CPU
- 迁移时会调整目标 CPU 上的 vruntime 偏移,避免因时间戳差异导致误判
- group scheduling(组调度)进一步将线程组、cgroup 视为整体,保障容器或用户会话级的公平性










