第3讲:进程调度
多任务系统根据任务调度的模式不同,可以分为两类:
- 抢占式多任务(preemptive multitasking)。“抢占”就是强制挂起正在执行的进程。
- 非抢占式多任务(coorperative multitasking)。除非进程自己主动停止(让步,yielding),否则会一直执行。
进程可分为:IO消耗型、CPU消耗型。对于交互式应用和桌面系统,IO型的优先级要高,保证其能快速响应;同时也要兼顾“最大系统利用率”(高吞吐量)。
多数用户图形界面程序(GUI)都属于IO密集型,即便它们从不读取或者写入磁盘,它们也会在多数时间里都在等待来自鼠标或者键盘的用户交互操作。
Linux 调度程序很多,比如 O(1) 调度(更适合大服务器,而不适合存在很多交互程序的桌面系统)。本书主要讲解的是 CFS 完全公平调度算法。
一、调度方式
(1)优先级调度
- nice值(-20~19):值越大、优先级越低。
- 实时优先级(0-99)。值越大、优先级越高。任何实时进程的优先级都高于普通的进程。
(2)时间片
- 调度策略必须规定一个默认的时间片,这是进程运行的“基本单位”。
- CFS调度分配的是在一个调度周期内、处理器使用比例,而非时间片。
二、调度算法
Linux调度器是模块化实现的,“调度器类”允许多种不同的可动态添加的调度算法并存,调度属于自己范畴的进程。CFS 便是一个针对普通进程的调度类 SCHED_NORMAL
。
nice 值映射到时间片存在的问题?
也就是让不同 nice 值对应到绝对时间片,比如 0(nice)-100(time), 1-95...
- 无法同时适应 CPU 负载高和低两种情况。如果 CPU 负载较低,可能进程需要频繁切换,开销太大。
- nice 值越靠近边界、时间片波动越大。比如
18-10, 19-5
就变化了一倍。
就是说:“把进程的 nice值减小1”所带来的效果极大地取决于其 nice 的初始值。
- 由于时间片必须是定时器节拍的整数倍。这导致不同时间片之间最少差一拍(1ms 或 10ms),做不到细粒度控制。
- 某些特殊进程可能通过篡改优先级,打破公平原则,获得更多时间片。
二、CFS 调度
对于单核处理器来说没法做到完美调度(多个进程没法同时使用 cpu 资源)。CFS的做法是允许每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个运行进程,而不再采用分配给每个进程时间片的做法了。
CFS在所有可运行进程总数基础上计算出一个进程应该运行多久,而不是依靠 nice 值来计算时间片:越高的nice值(越低的优先级)进程获得更低的处理器使用权重
CFS 综合考虑了所有因素后,不断计算当前调度周期内每个进程的vruntime,实现动态调度。
CFS 的调度周期称为“目标延迟”,越小的调度周期将带来越好的交互性,同时也更接近完美的多任务。但是你必须承受更高的切换代价和更差的系统总吞吐能力。
关键:绝对的 nice 值不再影响调度决策:只有相对值才会影响处理器时间的分配比例。
nice=5 的进程的权重将是 nice=0 进程的 1/3。如果我们的目标延迟是20ms,那么这两个进程将分别获得15ms和 5ms 的处理器时间。比如我们的两个可运行进程的 nice 值分别是10和15,它们分配的时间片将是多少呢?还是15和 5ms!
CFS 调度的实现关键在于四个部分:
(1)时间记账。所有的调度器都必须对进程运行时间做记账。CFS 调度器实现为 struct sched_entity
。经过所有可运行进程总数的标准化得到虚拟运行时 vruntime。
虚拟时间是以 ns 为单位的,所以 vruntime 和定时器节拍不再相关。虚拟运行时间可以帮助我们逼近 CFS 模型所追求的“理想多任务处理器”:所有进程都被公平调度。
(2)进程选择。运行队列是红黑树(自平衡二叉搜索树 BST),利用快速查找特性可以迅速找到最小 vruntime 值的进程。
- 挑选下一个任务。在建树时便将最小 vruntime 缓存在 rb_leftmost 变量中,可以直接使用。
- 向 rb_tree 加入进程。当进程变为可运行状态(被唤醒)或通过 fork 调用第一次创建进程。利用 rb_tree “左节点永远小于右节点”的特性进行插入和缓存 rb_leftmost 的操作。
- 删除进程。当进程变为不可运行状态或终止(结束运行)时。
(3)调度器入口:
(4)睡眠与唤醒:
进程切换大致由这几步组成:
- 进程的调度是由内核管理的,因此首先会进行用户态到内核态的切换。
- 保存被中断进程的上下文。
- 修改被中断进程的状态信息,并加入到相应的状态队列。
- 调度一个新的进程,加载其上下文。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通