Linux 调度器深度解析:CFS 完全公平调度,原来如此简单
一、旧调度器的问题:什么叫“不公平”?
面试时被问到Linux进程调度,如果回答还停留在“O(1)调度器”和“固定时间片”,那就有点跟不上时代了。这套在Linux 2.6.23之前主力的调度算法,名字听着很高效,实际用起来却埋了不少坑。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
当时的设计思路很直接:给每个进程分配一个固定的时间片,比如100毫秒,然后按照优先级轮着跑。听上去很公平,对吧?但实际操作中,几个根本性的问题就暴露出来了。
首当其冲的就是交互体验。想象一下,你正在用文本编辑器码字,后台同时跑着一个编译任务。如果两者优先级一样,各拿100毫秒的时间片轮流上CPU。那么当你敲下键盘,编辑器可能得等完编译进程那100毫秒才能响应,这种卡顿感对用户来说是实实在在的。
更深层的问题在于,当时的优先级系统有点像“黑魔法”。怎么决定一个nice值为-5的进程该拿多少时间片?并没有一个清晰的数学模型,全靠经验和一些启发式规则来拍脑袋。一旦优先级层次复杂起来,调整和维护就变成了一场噩梦。
更麻烦的是,CPU使用率的统计也不够准。O(1)调度器需要自己去猜测一个进程到底是“交互型”还是“计算密集型”,猜错了,调度就会出问题,该响应的不响应,该让出的不让出。
正是这些“不公平”和“不优雅”,催生了CFS的诞生。它干脆抛弃了“时间片”这个传统概念,用一种更精妙的思路来重新定义公平。
二、CFS的核心思想:虚拟时钟
CFS,全称完全公平调度器,它的核心秘密武器是一个叫vruntime(虚拟运行时间)的东西。你可以把它理解为每个进程在“公平裁判”的时钟下,已经消耗的时间。
它的目标用一句话就能说清:让所有进程的vruntime尽可能趋于相等。谁在这个虚拟时钟里跑得少,谁就排到前面去。这就像一场长跑,裁判不看谁实际反赌,而是看谁的“加权耗时”少,以此来调整下一段的出发顺序。
调度器每次要做的决策异常简单:从所有准备就绪的进程里,选出那个vruntime最小的来运行。进程在真实CPU上每运行一刻,它的vruntime就会增加一点。这样一来,跑得多的进程vruntime上去得就快,自然就往后排,让位给跑得少的。
但问题来了,如果所有进程的vruntime增速都一样,那优先级(nice值)还有什么意义?高优先级进程凭什么获得更多CPU时间呢?这就引出了下一个关键设计。
三、nice值与权重:vruntime的增速不一样
CFS实现优先级的秘诀,不在于给谁“插队”,而在于巧妙地控制每个进程vruntime的“流速”。这里的关键是权重。
每个nice值都对应一个预设的权重,以nice=0为基准,权重是1024。优先级提高(nice值降低),权重按比例增加(约25%);优先级降低(nice值升高),权重则减少(约20%)。
核心公式是这样的:
vruntime增量 = 实际运行时间 × (基准权重 / 该进程权重)
这意味着什么呢?高优先级进程(权重高)干同样的活儿,“虚拟耗时”却增加得慢。举个直观的例子:同样在物理CPU上跑了10毫秒,一个高优先级进程的vruntime可能只涨了3毫秒,而一个低优先级进程的vruntime可能涨了30毫秒。

如此一来,在调度器的排序队列里,高优先级进程就能更频繁地被选中,实际上也就获得了更多的CPU资源。优先级不再是生硬的“时间片加倍”,而是通过数学计算融入到了公平的度量体系里,非常优雅。
四、红黑树:CFS的“选人”数据结构
道理讲明白了,那具体怎么高效地“选出vruntime最小的那一个”呢?总不能每次都遍历所有进程吧?Linux内核的选择是使用红黑树。
所有可运行的进程都被组织成一颗红黑树,而排序的“键”正是它们的vruntime值。这样一来,vruntime最小的进程,自然就在树的最左边。

每次需要调度时,直接取最左节点就行了。红黑树查找的时间复杂度是O(log n),但内核做了优化,它会缓存这个最左节点的指针,使得挑选下一个进程的操作在常数时间内就能完成。
所以,整个CFS的调度循环可以浓缩成三步:
- 从红黑树摘下最左节点(vruntime最小)投入运行。
- 进程运行时,根据其权重更新它的vruntime(注意,权重高的涨得慢)。
- 进程运行一段时间后(或因等待I/O而放弃CPU),根据更新后的vruntime,重新插入红黑树,等待下一次被选中。
这个循环周而复始,驱动着所有进程的vruntime向一个共同的平衡点靠拢,这就是“完全公平”的动态实现。
五、调度周期与时间片:CFS怎么决定一次跑多久?
虽然CFS没有固定时间片,但它引入了调度周期的概念。你可以把它理解成一次“公平分配回合”。默认情况下,这个周期在低负载时约为6毫秒,高负载时会动态增加到48毫秒。
在一个调度周期内,调度器的目标是让所有就绪进程都能至少运行一次。每个进程能分到的时间,是根据它的权重按比例计算的:
进程分得时间 = 调度周期 × (该进程权重 / 所有进程权重之和)
举个例子,假设三个进程A、B、C的权重分别是1024、512、512,调度周期是6毫秒:
- A的时间 = 6ms × (1024/2048) = 3ms
- B的时间 = 6ms × (512/2048) = 1.5ms
- C的时间 = 6ms × (512/2048) = 1.5ms
当然,如果进程太多,按比例算下来每个进程分到的时间可能非常短,频繁的进程切换会造成大量开销。因此CFS设置了一个底线——min_granularity(最小粒度,默认0.75毫秒)。如果算出来的时间低于这个值,就按这个最小值来,避免无意义的频繁切换。
六、Linux完整调度层次:CFS不是唯一的
需要明确的是,CFS并非Linux调度世界的全部。Linux的调度体系是分层的,不同类型的任务走不同的通道。

处于顶端的是实时调度类(SCHED_FIFO或SCHED_RR)。这类进程(比如某些音视频流处理、工业实时控制)一旦就绪,就可以抢占所有普通CFS进程。对于它们,nice值毫无意义,它们有自己的实时优先级(1-99)。为了保证系统不被一个死循环的实时进程拖垮,通常需要非常谨慎地使用。
而我们日常运行的绝大多数应用程序、后台服务,都属于普通调度类,默认就在CFS的管理之下,通过调整nice值来影响其CPU资源的分配比例。
七、实战:如何调整进程优先级?
理论懂了,动手试试才是关键。调整进程优先级,最常用的命令就是nice和renice。
启动时指定nice值(范围-20到+19,越低优先级越高):
nice -n -5 ./my_program # 以nice=-5启动(通常需root权限)
nice -n 10 ./background_job # 以低优先级启动,普通用户只能调低(增大nice值)
调整一个已在运行进程的nice值:
renice -n 5 -p 1234 # 将PID为1234的进程nice值改为5
查看进程的调度信息:
ps -o pid,ni,cls,comm -p 1234
# 输出示例:
# PID NI CLS COMMAND
# 1234 5 TS my_program
# CLS列:TS代表SCHED_OTHER(即CFS),RR/FIFO代表实时调度
对于实时任务(需root权限):
chrt -f 50 ./realtime_task # 以SCHED_FIFO策略,实时优先级50运行
chrt -r 50 ./realtime_task # 以SCHED_RR策略,实时优先级50运行
在C程序中直接设置:
#include
// 设置为实时调度(需要CAP_SYS_NICE权限)
struct sched_param param = { .sched_priority = 50 };
sched_setscheduler(0, SCHED_FIFO, ¶m);
// 对于普通进程,调整nice值
nice(10); // 降低优先级(增大nice值)
八、CFS的边界情况:新进程和睡醒进程怎么处理
CFS的设计非常周全,它特别考虑了两个边界场景。
首先是新进程的加入。如果新进程的vruntime从0开始,而其他老进程的vruntime已经积累到几百毫秒了,那么这个新进程会因为vruntime极小而长时间霸占CPU,直到“追上”大家,这显然不合理。因此,新进程的vruntime会被初始化为当前CPU运行队列中的min_vruntime,这样它就站在了和大家差不多的起跑线上。
其次是睡眠进程的唤醒。进程在睡眠(比如等待I/O)期间,vruntime是不增加的。当它醒来时,自己的vruntime可能远小于那些一直在运行的兄弟,如果直接参与竞争,又会不公平地长期霸占CPU。CFS的做法是:唤醒时,将其vruntime设置为max(其原始vruntime, min_vruntime - sched_latency)。这相当于给了它一个合理的“补偿”,让它能尽快获得服务,但又不会过度补偿,保证了整体的公平性。
九、高频面试题精析
聊到这里,几个经典的面试题就很好回答了。
Q:CFS的“完全公平”到底指什么?
A:并非指每个进程获得绝对相同的物理CPU时间,而是指每个进程都能获得按其权重比例分配的、理想化的CPU时间。最终目标是让所有进程的vruntime(虚拟运行时间)趋向一致,这才是它衡量公平的尺子。
Q:nice值和priority(PRI)有什么区别?
A:我们用户能用nice命令设置的是nice值(-20到+19)。而ps等命令看到的PRI(优先级)是内核内部使用的值,它等于20加上nice值。实时进程有另一套完全独立的实时优先级(1-99),不在这个体系里。
Q:为什么像Redis这样的高性能服务,反而建议谨慎使用或降低实时优先级?
A:这是一个重要经验。实时进程一旦处于可运行状态,就会抢占所有普通进程。如果它陷入死循环或一个长耗时操作,可能导致整个系统无法响应。像Redis这类依赖事件循环和IO复用的服务,其高性能不依赖于独占CPU,使用默认的CFS调度,配合合理的nice值调整通常更为安全和稳定。
Q:如何让一个程序近乎“独占”一个CPU核心?
A:有几种层级的方法:1) 使用chrt设为最高实时优先级(风险高);2) 使用taskset绑定进程到特定CPU,并结合内核启动参数isolcpus将该CPU从通用调度器中隔离;3) 利用cgroup的cpuset子系统,在容器化环境中进行精细的CPU资源隔离和分配。
十、结语
理解了CFS,你就掌握了Linux公平调度的灵魂。记住这三个核心支柱:
- vruntime(虚拟运行时间):一把衡量公平的、统一的尺子。
- 红黑树(最左节点选择):一套高效、稳定地找出“最该运行进程”的机制。
- 权重(由nice值决定):一个将优先级差异巧妙转化为vruntime不同“流速”的数学桥梁。
正是这三者的精妙组合,让Linux内核能够在瞬息之间,在上百个进程间做出精准的调度决策,既保证高优先级任务获得所需资源,又确保低优先级任务不会被彻底饿死。这才是现代操作系统调度艺术背后的精密工程。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
迷途领航,不再陷入RPA人人可用的口号误区
要说RPA一线大厂和广大厂商都认可和推崇的愿景,那就非“RPA人人可用”莫属了 这不仅仅是技术提供方的终极目标,更是无数正埋头进行数字化转型的组织梦寐以求的图景。道理很简单:一旦RPA能拆除所有使用门槛,实现真正的“人人可用”,就意味着每个组织都能快速引入流程自动化,实实在在地看到效率和成本的优化。
办公自动化软件的应用价值
办公自动化软件的应用价值 提到办公自动化(OA)软件,大多数人首先想到的可能是文档处理或者流程审批。但它的真正价值远不止于此。说到底,它是一套旨在优化组织运作的系统工程,其核心价值可以概括为四个关键词。 连接 这是OA系统的基础。想象一下,它将分散在局域网和互联网上的不同部门、乃至员工个人,全部串联
RPA在信托行业科技创新、降本增效的价值及作用
RPA在信托行业科技创新、降本增效的价值及作用 在数字化转型的浪潮中,RPA(机器人流程自动化)正悄然扮演着“数字员工”的角色。它依据既定规则,一丝不苟地处理那些重复、枯燥的海量业务,不仅确保了惊人的准确度,更将人力从低价值劳动中彻底解放出来。这省下的,可是企业最宝贵的人力资源和与之相关的显性与隐性
RPA技术的核心技术有哪些?
RPA技术的核心技术有哪些? 说到RPA的技术内核,绕不开三大支柱:流程控制技术、机器人技术和协调器技术。这其中,流程控制技术堪称机器人的“大脑”,负责指挥和执行所有任务。在现代RPA平台上,我们可以通过可视化的流程建模,或者下发清晰的任务指令,来快速告诉机器人“你要做什么”。 一旦任务明确,这些指
Pada - AI角色聊天平台,支持多模态互动体验
Pada是什么 简单来说,Pada是原“问小白”App一次重要的战略升级。它不再只是一个综合性的AI工具,而是蜕变为一个全新的平台,定位非常清晰:一个专注于 **「AI角色聊天与共创宇宙」** 的社区。在这里,你可以找到丰富的虚拟角色,进行沉浸式的对话,甚至通过语音、图片等多种方式互动。它的核心,是
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

