首页 游戏 软件 资讯 排行榜 专题
首页
业界动态
Linux 调度器深度解析:CFS 完全公平调度,原来如此简单

Linux 调度器深度解析:CFS 完全公平调度,原来如此简单

热心网友
75
转载
2026-04-22

一、旧调度器的问题:什么叫“不公平”?

面试时被问到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资源的分配比例。

七、实战:如何调整进程优先级?

理论懂了,动手试试才是关键。调整进程优先级,最常用的命令就是nicerenice

启动时指定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内核能够在瞬息之间,在上百个进程间做出精准的调度决策,既保证高优先级任务获得所需资源,又确保低优先级任务不会被彻底饿死。这才是现代操作系统调度艺术背后的精密工程。

来源:https://www.51cto.com/article/839641.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

万字长文彻底搞懂 Linux proc 文件系统
业界动态
万字长文彻底搞懂 Linux proc 文件系统

从 proc cpuinfo 到 proc sys:读懂 Linux 深处的“动态信息宝库” 想真正掌控 Linux 系统,就绕不开 proc 文件系统。它远不止一个普通的目录,而是内核与用户空间沟通的核心桥梁,更是解锁系统监控、调试与性能调优的关键钥匙。与那些躺在磁盘上的普通文件系统不同,p

热心网友
04.22
Linux 调度器深度解析:CFS 完全公平调度,原来如此简单
业界动态
Linux 调度器深度解析:CFS 完全公平调度,原来如此简单

一、旧调度器的问题:什么叫“不公平”? 面试时被问到Linux进程调度,如果回答还停留在“O(1)调度器”和“固定时间片”,那就有点跟不上时代了。这套在Linux 2 6 23之前主力的调度算法,名字听着很高效,实际用起来却埋了不少坑。 当时的设计思路很直接:给每个进程分配一个固定的时间片,比如10

热心网友
04.22
图解 Linux 内存管理:虚拟内存、malloc、缺页中断,一次搞懂
业界动态
图解 Linux 内存管理:虚拟内存、malloc、缺页中断,一次搞懂

Linux 内存管理:一场由“懒惰”驱动的效率革命 Linux 内存管理的精妙之处,在于它巧妙地将几种“懒惰”哲学叠加在一起。正是这套组合拳,让系统能够在有限的内存资源上,高效地运行成百上千个进程,同时还能牢牢守住进程间的隔离墙。 上一期我们探讨文件系统时,提到了Page Cache如何占用内存,以

热心网友
04.22
Redis BGSAVE 之后内存暴涨?不是 bug,是 Linux 在保护你的数据
业界动态
Redis BGSAVE 之后内存暴涨?不是 bug,是 Linux 在保护你的数据

一、从一个问题开始:fork() 复制了什么? 想象这样一个场景:一个进程已经加载了10GB的数据到内存中,然后它调用了fork()。如果这个系统调用需要完整复制这10GB数据,那么整个服务恐怕会卡顿数秒,这在像Redis这样的高性能系统中是完全不可接受的。 但现实是,fork()几乎在瞬间就完成了

热心网友
04.22
Linux crontab 不执行?90% 问题都出在这八个坑(附排查方法)
业界动态
Linux crontab 不执行?90% 问题都出在这八个坑(附排查方法)

彻底告别定时任务噩梦:一份来自生产环境的crontab避坑指南 凌晨三点,备份脚本在终端里跑得完美无缺,你信心满满地将它加入crontab,然后安心睡去。第二天一早,迎接你的却是磁盘告警的邮件——任务根本没执行,数据原地未动。这种场景,恐怕是每一位Linux运维新手都经历过的“乘人礼”。 事实上,9

热心网友
04.22

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

iPhone16之间如何快速传输App?详细步骤解析
iphone
iPhone16之间如何快速传输App?详细步骤解析

通过AirDrop功能,可在iPhone16之间快速传输已安装的App,无需重新下载。 省去重新下载的等待,直接在两部iPhone 16之间“搬运”已经安装好的App——这个用AirDrop传App的功能,确实方便。不过,想顺利操作,有几个关键前提得先摆正。 准备工作与条件确认 开始之前,最好花一分

热心网友
04.22
iPhone17设备名称怎么修改?详细步骤教程
iphone
iPhone17设备名称怎么修改?详细步骤教程

修改iPhone17设备名称的核心步骤 想给你的iPhone17换个独具特色的名字吗?其实很简单,整个操作的核心路径就在「设置」>「通用」>「关于本机」>「名称」里,几步就能完成自定义。 为什么要修改iPhone17的设备名称? 给iPhone17改个名,可不仅仅是图个新鲜。它在蓝牙配对、使用Air

热心网友
04.22
iPhone14隐藏ID怎么解除?详细步骤与注意事项
iphone
iPhone14隐藏ID怎么解除?详细步骤与注意事项

解除iPhone14隐藏ID的核心方法是联系原机主或提供购买凭证,通过官方渠道重置Apple ID 手里突然多出一台被锁的iPhone 14,用起来处处受限,这事儿确实头疼。好消息是,只要遵循官方路径,问题基本都能解决。关键在于,你得有耐心走完正规流程。 什么是iPhone隐藏ID? 简单来说,iP

热心网友
04.22
怎么查找我的iPhone17位置?
iphone
怎么查找我的iPhone17位置?

通过“查找”应用或iCloud网站,登录Apple ID即可实时定位iPhone 17,即使设备离线也能显示最后已知位置。 使用“查找”应用定位iPhone 17 如果你手边还有别的苹果设备,比如iPad或者Mac,最省事的方法就是直接用上面的“查找”应用。打开应用,登录和iPhone 17同一个

热心网友
04.22
iPhone 16通知权限设置与微信提示音修复指南
iphone
iPhone 16通知权限设置与微信提示音修复指南

iPhone 16通知权限设置与微信提示音修复指南 微信消息突然“静音”了?先别急着怀疑手机坏了。在iPhone 16上,通知体系和声音管理比以往更精细,有时只是某个开关没到位。接下来,咱们就把系统通知中心、应用权限、勿扰模式这几个关键环节捋清楚,帮你快速找回失联的提示音,避免错过重要信息。 iPh

热心网友
04.22