2. 进程调度基础概念:进程状态模型、上下文切换、调度延迟与吞吐量
在深入 O(1) 与 CFS 调度器架构之前,必须建立坚实的进程调度基础。本节将围绕三个核心概念展开:进程状态模型(描述进程生命周期)、上下文切换(调度执行的具体代价)以及调度延迟与吞吐量(衡量调度器性能的关键指标)。这些概念是所有调度算法选型的基石。
2.1 进程状态模型:就绪、运行与阻塞
操作系统通过状态机管理进程的生命周期。Linux 内核将进程抽象为三种基本状态,以及两种辅助状态(创建与终止)。调度器主要关注前三种状态的转换。
核心状态定义:
- 运行(Running): 进程正在 CPU 上执行指令。在单核系统中,同一时刻只有一个进程处于此状态。
- 就绪(Ready): 进程已具备运行条件,等待 CPU 调度。它位于调度器的就绪队列中,随时可以被选中执行。
- 阻塞(Blocked): 进程因等待某事件(如 I/O 完成、信号量、定时器)而暂停执行。即使 CPU 空闲,该进程也无法运行。
下图展示了进程状态之间的典型转换路径,以及调度器介入的关键点:
调度器视角: 调度器只关心“就绪”和“运行”两个状态。阻塞状态的进程被移出调度队列,不参与 CPU 竞争。当进程从阻塞变为就绪时,调度器将其重新插入就绪队列。
2.2 上下文切换:调度的核心代价
当调度器决定将 CPU 从当前进程切换到另一个进程时,必须执行上下文切换。这是调度操作的主要开销来源,直接影响系统性能。
上下文切换的内容:
- 硬件上下文: CPU 寄存器(通用寄存器、程序计数器 PC、栈指针 SP)、状态寄存器。
- 内存上下文: 页表基地址(切换地址空间,涉及 TLB 刷新)。
- 内核栈: 每个进程拥有独立的内核栈,切换时需切换内核栈指针。
上下文切换的代价分析:
| 代价类型 | 具体开销 | 影响程度 |
|---|---|---|
| 直接 CPU 开销 | 保存/恢复寄存器、切换栈指针、执行调度算法 | 微秒级(通常 1-10 μs) |
| 缓存污染 | L1/L2 缓存、TLB 失效,新进程需重新加载数据 | 毫秒级性能下降(间接代价更大) |
| 地址空间切换 | 切换 CR3 寄存器(x86),刷新 TLB | 数百纳秒至微秒 |
关键认知: 上下文切换的“隐藏成本”远大于指令执行时间。频繁切换会导致缓存颠簸(Cache Thrashing),使系统吞吐量急剧下降。调度器设计必须在“公平性”与“切换开销”之间取得平衡。
下图展示了上下文切换的完整流程:
2.3 调度延迟与吞吐量:性能度量指标
调度器的性能通过两个核心指标衡量:调度延迟(响应速度)和吞吐量(处理能力)。这两个指标通常相互制约。
2.3.1 调度延迟
调度延迟指从进程变为就绪状态到它实际开始运行所经历的时间。它直接决定了系统的交互响应体验。
- 抢占延迟(Preemption Latency): 从外部事件(如硬件中断)发生到调度器开始执行调度决策的时间。
- 调度决策延迟(Scheduling Decision Latency): 调度器遍历就绪队列、选择下一个进程所花费的时间。
- 切换延迟(Switch Latency): 执行上下文切换本身的时间。
2.3.2 吞吐量
吞吐量衡量系统在单位时间内完成的进程数量或工作量。对于批处理系统,吞吐量是首要优化目标。
- 进程吞吐量: 单位时间内完成的进程数。
- CPU 利用率: CPU 处于“忙”(执行用户代码或内核代码)的时间比例。高吞吐量通常伴随高 CPU 利用率。
延迟与吞吐量的权衡:
| 调度策略倾向 | 调度延迟 | 吞吐量 | 典型场景 |
|---|---|---|---|
| 交互优先(如 CFS 默认) | 低(毫秒级) | 中等 | 桌面系统、Web 服务器 |
| 吞吐优先(如批处理调度) | 高(秒级) | 高 | 科学计算、视频渲染 |
| 实时调度(如 FIFO/RR) | 极低(微秒级) | 低 | 工业控制、音频处理 |
调度器设计目标: 理想的调度器应在保证可接受的调度延迟前提下,最大化系统吞吐量。O(1) 调度器通过位图算法实现常数时间的调度决策,以降低调度延迟;CFS 则通过红黑树和虚拟运行时间实现完全公平,同时保持对数时间复杂度的调度延迟。
下图展示了调度延迟与吞吐量之间的典型关系曲线:
2.4 基础概念与调度器选型的关联
理解上述基础概念后,可以建立与 O(1) 和 CFS 调度器架构的直接关联:
| 基础概念 | 对 O(1) 调度器的影响 | 对 CFS 调度器的影响 |
|---|---|---|
| 进程状态模型 | O(1) 使用 140 级优先级队列,就绪进程按优先级入队;阻塞进程被移出活跃队列。 | CFS 使用红黑树管理就绪进程,键值为虚拟运行时间;阻塞进程从树中移除。 |
| 上下文切换 | O(1) 通过位图快速找到最高优先级队列,减少调度决策时间,间接降低切换频率。 | CFS 每次调度都需从红黑树中选取最左节点(最小 vruntime),切换次数与进程数对数相关。 |
| 调度延迟 | O(1) 保证调度决策时间为常数 O(1),延迟可预测,适合实时性要求高的场景。 | CFS 调度延迟为 O(log N),N 为进程数;通过目标延迟(targeted latency)控制最大延迟。 |
| 吞吐量 | O(1) 的静态优先级可能导致低优先级进程饥饿,但整体吞吐量稳定。 | CFS 通过公平分配 CPU 时间,避免饥饿,但频繁切换可能降低极端负载下的吞吐量。 |