当前位置: 首页 > news >正文

第22天:CFS 调度:完全公平调度的核心原理

从"抢跑"到"公平":Linux 进程调度的进化之路

想象一下这样的场景:在一个繁忙的餐厅里,厨师需要为几十桌客人准备饭菜。如果厨师只专注于一桌客人的菜,其他桌的客人可能会等得不耐烦;但如果厨师频繁切换,又会影响做菜的效率。Linux 内核中的进程调度器就像这位厨师,它需要在多个进程之间分配 CPU 时间,既要保证每个进程都能得到执行机会,又要尽可能提高系统整体性能。

在 Linux 2.6.23 版本之前,内核使用的是基于优先级的 O(1) 调度器。这种调度器虽然效率很高,但存在一个严重的问题:高优先级进程可能会"饿死"低优先级进程。为了解决这个问题,Ingo Molnar 引入了 CFS(Completely Fair Scheduler,完全公平调度器),它的核心思想是:让每个进程都能公平地获得 CPU 时间


CFS 的核心原理

1. 公平的本质:虚拟运行时间

CFS 的核心创新在于引入了虚拟运行时间(Virtual Runtime)的概念。虚拟运行时间不是进程实际占用的 CPU 时间,而是经过"权重"加权后的时间。

/* 虚拟运行时间的计算逻辑 */ static u64 sched_vruntime(struct task_struct *p) { struct sched_entity *se = &p->se; /* 虚拟时间 = 实际运行时间 * NICE_0_LOAD / 进程权重 */ return se->vruntime; }

这里的关键公式是:

虚拟运行时间 = 实际运行时间 × (1024 / 进程权重)

其中NICE_0_LOAD = 1024是默认进程(nice=0)的权重。

2. 红黑树:高效的调度队列

CFS 使用红黑树来管理所有可运行的进程。树的键值是进程的虚拟运行时间vruntime,树的最左节点就是虚拟运行时间最小的进程,也就是下一个应该被调度的进程。

struct cfs_rq { struct rb_root tasks_timeline; /* 红黑树的根节点 */ struct rb_node *rb_leftmost; /* 最左节点(下一个要调度的进程)*/ unsigned int nr_running; /* 队列中的进程数量 */ unsigned int h_nr_running; /* 高优先级进程数量 */ u64 min_vruntime; /* 最小虚拟运行时间 */ /* ... */ };

3. 调度时机:何时选择新进程

CFS 会在以下几种情况下重新选择下一个要运行的进程:

  1. 进程主动放弃 CPU(如调用sleep()
  2. 时间片耗尽
  3. 更高优先级进程唤醒
  4. 周期性时钟中断(通常每毫秒)
static void check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) { unsigned long ideal_runtime, delta_exec; /* 计算理想运行时间 = 调度周期 / 进程数量 */ ideal_runtime = sched_slice(cfs_rq, curr); /* 计算当前进程自上次调度以来的运行时间 */ delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; /* 如果超过理想时间片,触发抢占 */ if (delta_exec > ideal_runtime) resched_curr(rq_of(cfs_rq)); }

关键数据结构解析

task_struct 中的调度相关字段

每个进程都有一个task_struct结构,其中与调度相关的关键字段如下:

struct task_struct { /* 调度实体,包含虚拟运行时间等信息 */ struct sched_entity se; /* 进程优先级相关 */ int prio; /* 动态优先级(0-139)*/ int static_prio; /* 静态优先级(100-139)*/ int normal_prio; /* 常规优先级 */ unsigned int rt_priority; /* 实时优先级 */ /* 调度策略 */ unsigned int policy; /* SCHED_NORMAL/SCHED_FIFO/SCHED_RR */ /* 进程状态 */ volatile long state; /* TASK_RUNNING/TASK_INTERRUPTIBLE 等 */ /* ... */ };

sched_entity:调度实体

struct sched_entity { struct load_weight load; /* 进程权重,影响虚拟时间计算 */ struct rb_node run_node; /* 红黑树节点 */ struct list_head group_node; /* 组调度链表节点 */ u64 vruntime; /* 虚拟运行时间 */ u64 prev_vruntime; /* 上一次调度时的虚拟时间 */ u64 sum_exec_runtime; /* 累计实际运行时间 */ u64 prev_sum_exec_runtime; /* 上一次调度时的累计运行时间 */ /* ... */ };

实战:观察 CFS 调度行为

查看进程调度信息

使用ps命令查看进程的调度策略和优先级:

# 查看所有进程的调度策略 ps -eo pid,tid,class,rtprio,pri,nice,cmd # 输出示例: # PID TID CLS RTPRIO PRI NI CMD # 1234 1234 TS - 19 0 bash # 5678 5678 FF 99 1 -20 realtime_app

使用 chrt 命令修改调度策略

# 将进程设置为实时 FIFO 调度策略,优先级为 50 chrt -f -p 50 1234 # 将进程恢复为普通 CFS 调度 chrt -o -p 0 1234

查看内核调度统计

# 查看调度器统计信息 cat /proc/schedstat # 查看特定进程的调度信息 cat /proc/[pid]/sched

CFS 的优势与局限性

优势

  1. 公平性:每个进程都能获得公平的 CPU 时间片
  2. 低延迟:交互进程响应迅速
  3. 自适应:能够根据系统负载自动调整
  4. 简单优雅:相比 O(1) 调度器,代码更简洁

局限性

  1. 红黑树操作开销:虽然是 O(log n),但在进程数极多时仍有开销
  2. cache 友好性:频繁的进程切换会影响 CPU cache 效率
  3. 实时性:CFS 是通用调度器,实时性能不如 RT 调度器

互动讨论

  1. 思考题:如果系统中有一个 CPU 密集型进程和一个 I/O 密集型进程,CFS 会如何分配 CPU 时间?为什么 I/O 密集型进程通常能获得更好的响应性?

  2. 实践题:尝试使用chrt命令修改一个进程的调度优先级,然后使用tophtop观察它的 CPU 占用率变化。你能观察到什么现象?


请帮忙点赞收藏+关注,内容持续更新,感谢大家~~~

http://www.jsqmd.com/news/1099562/

相关文章:

  • Adobe-GenP 3.0:终极Adobe软件激活指南与使用技巧
  • Godot【使用篇】01:Hello World
  • AKShare:金融数据接口的架构哲学与实践反思
  • DeepSeek美化-为 DeepSeek 网页版引入 Obsidian Border 主题视觉风格
  • 想学落地实操,优先理工科还是经管类院校大数据
  • SPT-AKI Profile Editor:逃离塔科夫离线服务器存档修改终极指南
  • 当 AI Agent 学会长出免疫系统:从城堡防御到细胞防御的范式转换
  • 【VMware网络专家20年压箱底笔记】:多虚拟机通信必须绕开的4个致命陷阱(第3个连vCenter日志都不报错)
  • SSLsplit与OpenSSL深度集成:全面支持RSA、DSA、ECDSA密钥实战指南
  • 量子计算在化学模拟中的应用与iQCC算法解析
  • SMU 2026 Spring 天梯赛5题解
  • 大数据相关专业哪个最适合普通家庭孩子:2026年选专业,别只盯“高大上”,要看能不能落地
  • lambda表达式语法
  • 设备维修工工资低怎么办?3条破局思路与1个“万金油”技能
  • 如何用Goo Engine的4个魔法节点打造惊艳的动漫风格渲染
  • 几句话概括,MySQL 半同步中,after_commit 与 after_sync 有什么区别
  • MHMarkets迈汇:“惠普携手开放人工智能”
  • Kiran-cc-daemon插件开发完全手册:如何为麒麟桌面扩展新的控制功能
  • Moneta Markets亿汇:“人工智能合规风险升温”
  • 软件测试的四个阶段【单元测试、集成测试、系统测试和验收测试】
  • go: Fail-Fast Pattern
  • ​​​​​​​旧尺子量新人:当求职者的“新技能”遇上面试官的“旧思维”
  • 万能遥控器app,各类家具都可用,推荐安装!
  • 【MES】自研MES采集设备数据的坑
  • 【2026最新】Adobe InDesign:Id2026专业排版神器
  • 基于STM32单片机的颜色识别 TCS3200 RGB 检测系统2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • Python 基础入门:列表、字典、函数与类,一篇搞定核心概念本文将从零开始,带你掌握 Python 最核心的四个概念:列表、字典、函数和类。
  • emanjusaka——彼岸花开可奈何
  • 2026主流EPC项目协同平台横向选型与避坑评测
  • Manus小程序邀请码获取渠道+教程,附手机版+PC官网