Linux CFS(完全公平调度器)全面总结

  1. 核心设计理念

基本目标

• 完全公平:按权重而非绝对时间分配CPU份额

• 低开销:调度决策高效,适合大规模任务

• 良好响应性:保证交互式任务及时响应

公平性定义

• 公平 = 每个任务获得与其权重成比例的CPU时间

• 高优先级任务(低nice值)获得更多CPU时间

• 防止任何任务饿死

  1. 核心机制:虚拟运行时(vruntime)

vruntime计算

vruntime_increase = 实际运行时间 × (NICE_0_LOAD / 任务权重)

• 普通优先级任务:vruntime ≈ 实际运行时间

• 高优先级任务:vruntime增长更慢

• 低优先级任务:vruntime增长更快

vruntime的意义

• 衡量任务"已消耗的公平份额"

• vruntime越小,表示"吃亏"越多,优先级越高

• 调度目标:让所有任务的vruntime尽可能同步

  1. 数据结构与调度算法

红黑树管理

• 键值:任务的vruntime

• 最左节点:vruntime最小的任务,下一个被调度

• 操作效率:插入、删除、查找均为O(logN)

调度过程

  1. 选择任务:从红黑树取最左节点(vruntime最小)

  2. 任务运行:在CPU上执行

  3. 时间统计:更新实际运行时间和vruntime

  4. 重新插入:任务放回红黑树(如果仍可运行)

  5. 选择下一个:重复步骤1

  6. 时间管理与调度周期

关键参数

• sched_latency_ns:目标调度周期(默认24ms)

• sched_min_granularity_ns:最小时间片(默认3ms)

动态时间片计算

时间片 = max(调度周期/N, 最小时间片)

• 任务少时:每个任务获得较长时间片

• 任务多时:保证所有任务都能在周期内运行

  1. 任务状态处理

新任务创建

• vruntime初始化为当前运行队列的min_vruntime

• 给予适当补偿,避免过度"插队"

睡眠任务唤醒

• 关键机制:vruntime补偿 = -sched_latency_ns/2

• 目的:提升交互式任务响应性,但不破坏公平性

• 补偿值固定:不随任务数变化,保证最小响应性

实时进程关系

• 调度类优先级:RT > CFS > Idle

• 实时进程:总是抢占普通CFS任务

• 独立队列:实时进程使用优先级数组,CFS使用红黑树

  1. 多核与负载均衡

CPU间迁移

• vruntime调整:新vruntime = 原vruntime - 源CPUmin_vruntime + 目标CPUmin_vruntime

• 保持公平:迁移后维持相对进度位置

• 防止蜂拥:迁移不会获得不公平优势

负载均衡触发

• 周期性检查(每1-10ms)

• 新任务创建

• 任务唤醒

• CPU空闲时

  1. 抢占机制

调度触发点

  1. 主动调度:系统调用、阻塞操作
  2. 时钟中断:周期性检查(tick机制)
  3. 实时抢占:高优先级实时任务就绪
  4. 唤醒抢占:睡眠任务唤醒时可能抢占

完全抢占支持

• CONFIG_PREEMPT:允许内核态抢占

• 关键区域保护:持有自旋锁时不可抢占

• 中断返回路径:实际调度发生点

  1. 实际表现特性

优点

• ✅ 真正公平:按权重精确分配CPU时间

• ✅ 高扩展性:红黑树支持大量任务高效调度

• ✅ 良好响应性:交互式任务获得优先处理

• ✅ 自适应:动态调整时间片,平衡延迟和吞吐量

可调参数

查看和调整调度参数

/proc/sys/kernel/sched_latency_ns

/proc/sys/kernel/sched_min_granularity_ns

/proc/sys/kernel/sched_migration_cost_ns

  1. 总结

CFS是Linux调度器的重大进步,通过vruntime机制实现了真正的公平性:

• 核心创新:用vruntime替代传统时间片

• 高效实现:红黑树保证调度决策高效

• 公平保证:权重机制确保按比例分配CPU

• 响应性保障:睡眠补偿和完全抢占机制

• 多核优化:负载均衡和vruntime迁移保持跨CPU公平

这种设计使Linux能够同时满足服务器的高吞吐量和桌面的交互性需求,是现代操作系统调度算法的典范。

相关推荐
Kapaseker几秒前
如何写出高性能的Java Stream
android·java
想唱rap2 分钟前
哈希(C++)
服务器·开发语言·c++·算法·哈希算法
skywalk81633 分钟前
为什么Linux系统里用户id和组id不一样?怎么改成一样呢?
linux·服务器
HIT_Weston4 分钟前
72、【Ubuntu】【Hugo】搭建私人博客:Git 下载方式对比
linux·git·ubuntu
野生风长9 分钟前
从零开始的C语言:文件操作与数据管理(下)(fseek,ftell,rewind,文件的编译和链接)
android·java·c语言·开发语言·visual studio
百锦再10 分钟前
UniApp与UniApp X:跨平台开发的范式革命与全面技术解析
服务器·ai·uni-app·k8s·core·net
武子康11 分钟前
Java-210 Spring AMQP 整合 RabbitMQ:JavaConfig 注解配置、RabbitTemplate 发送/同步接收与坑位速查
xml·java·spring·消息队列·rabbitmq·java-rabbitmq·mq
五阿哥永琪14 分钟前
java基础 异常(Exception和Error)
java·开发语言
gaize121315 分钟前
腾讯云和阿里云谁家更合算,性价比更高
服务器
黑头人15 分钟前
Error: JAVA_HOME is not set and Java could not be found
java·开发语言