Skip to content

入门:调度概念、目标与抢占式/非抢占式

基于通用操作系统概念 · 核于 2026-08

速查

  • CPU 调度:在内存中的多个就绪进程之间分配 CPU——决定"谁先运行、运行多久"。本质是对有限 CPU 资源的时分复用。
  • 调度时机:进程从运行→等待(IO/睡眠)、运行→就绪(时间片用完/被抢占)、等待→就绪(IO 完成)、运行→终止——前两类触发非抢占式也调度,后两类只在抢占式才调度。
  • 抢占式(Preemptive):调度器可强制从运行进程手中夺回 CPU(时钟中断到/更高优先级就绪)。响应快、公平,但切换开销大、有竞态(需同步)。代表:Linux/Windows/macOS。
  • 非抢占式(Non-preemptive / Cooperative):一旦进程获得 CPU 就运行到自愿让出(IO 阻塞/结束/主动 yield)为止,调度器不能强抢。简单、无竞态,但一个死循环就拖垮全系统。代表:早期 Windows 3.1/Mac OS 9、协程调度。
  • 四大目标:①公平(每个进程都能得到 CPU,不饿死);②高吞吐(单位时间完成更多作业);③快响应(交互用户从输入到首响应的时间短);④低周转(作业从提交到完成的总时间短)。这些目标相互冲突——求吞吐则 SJF/FCFS,求响应则 RR。
  • CPU 密集型(CPU-bound):进程大部分时间在算 CPU(如编译、科学计算、视频编码),CPU 调度时给它长一点的时间片减少切换;这类进程是吞吐瓶颈
  • IO 密集型(IO-bound):进程大部分时间在等 IO(如键盘/网络/磁盘交互的编辑器/浏览器/数据库),CPU 调度时让它们频繁短时运行、用完立刻让出 CPU 去 IO。IO 密集型进程多 → 提升系统并发度
  • 调度器(Scheduler)vs 分发器(Dispatcher):调度器是策略——从就绪队列选下一个进程(FCFS/SJF/RR...);分发器是机制——把 CPU 控制权交给选中进程(上下文切换、切换用户态、跳到进程入口),有分发延迟(微秒级)。
  • 五种基本算法:FCFS(先来先服务,公平但有护航效应)、SJF(短作业优先,平均等待最优但饥饿)、RR(轮转,交互好)、优先级(按优先级,低优先级饥饿需老化)、MLFQ(多级反馈队列,动态调整,现代 OS 鼻祖)。
  • 甘特图(Gantt Chart):用横轴时间条可视化调度过程,每个进程占一段连续时间——是计算平均等待/周转时间的必备工具。
  • 护航效应(Convoy Effect):FCFS 下,一个长作业先到会拖累后面所有短作业——就像高速公路上一辆慢车后面拖一串快车,整体平均等待时间暴涨。
  • 饥饿(Starvation)与老化(Aging):SJF/优先级调度下,低优先级或长作业可能永远等不到 CPU(饥饿)。解法是老化——随等待时间增长逐步提升优先级,最终必能执行。
  • 进阶顺序调度算法详解调度性能指标与计算参考

一、CPU 调度是什么:时分复用 CPU

一台机器 CPU 核数有限(如 4 核 8 核),但要同时跑几十上百个进程。OS 通过时分复用——把 CPU 时间切成极短的时间片(毫秒级),让进程轮流占用,因为切换极快(毫秒内),用户感觉多个进程"同时"在跑。这个"决定谁占用、占多久"的机制就是 CPU 调度:

   就绪队列:  P1  P2  P3  P4  P5   ← 都想用 CPU


              ┌──────────┐
              │  调度器  │  ← 从队列选下一个(策略:FCFS/SJF/RR...)
              └────┬─────┘
                   │ 选中 P2

              ┌──────────┐
              │  分发器  │  ← 上下文切换,把 CPU 交给 P2(机制)
              └────┬─────┘

              CPU 运行 P2 一个时间片
                   │ 时间片到 / P2 阻塞

              P2 回队列(就绪)或等 IO(阻塞),调度器再选下一个
  • 调度器(scheduler)策略层,按算法从就绪队列选下一个进程。
  • 分发器(dispatcher)机制层,完成上下文切换(保存当前进程寄存器、加载下一进程寄存器、切用户态、跳到入口),有分发延迟(dispatch latency,约微秒级)。
  • 分两层的原因:策略与机制分离,便于换算法而不动切换机制——Linux 早年用 O(1) 调度器,后换成 CFS(完全公平),切换机制不变。

二、调度时机:什么时候需要调度

CPU 调度发生在进程状态切换的四个时刻,决定了抢占式 vs 非抢占式的边界:

                  ┌─────────┐
        ┌────────>│ 运行 Running│<────────┐
        │         └────┬────┘         │
        │              │              │
   时间片用完/被抢占   主动/被动     选中执行
   (抢占式才能)     等 IO/结束    (调度器选它)
        │              │              │
        ▼              ▼              │
   ┌─────────┐   ┌─────────┐    ┌─────────┐
   │ 就绪 Ready│   │ 等待 Wait │    │  ...    │
   └─────────┘   └────┬────┘    └─────────┘
        ▲              │
        │           IO 完成
        └──────────────┘

四个切换点:

  1. 运行 → 等待(进程主动 IO/睡眠/等信号):非抢占式和抢占式都会调度。
  2. 运行 → 就绪(时间片用完/被更高优先级抢占):只有抢占式才调度(非抢占式不会从运行进程手中夺 CPU)。
  3. 等待 → 就绪(IO 完成唤醒):只有抢占式才调度(刚唤醒的进程优先级可能更高)。
  4. 运行 → 终止(进程退出):非抢占式和抢占式都会调度。
  • 非抢占式:只在 1、4 调度(进程自愿让出)。
  • 抢占式:在 1、2、3、4 都调度(可强抢 CPU)。

三、抢占式 vs 非抢占式

维度抢占式(Preemptive)非抢占式(Non-preemptive)
CPU 让出方式被动,被调度器强抢(时钟中断/更高优先级就绪)主动,进程自愿让出(IO/结束/yield)
响应性好(高优先级/交互可立即抢占)差(一个长作业霸占 CPU 时其他全等)
公平性好(时间片保证每个进程都能跑)差(先到的长作业拖死后续)
切换开销大(频繁抢占)小(仅自愿让出时切换)
并发安全需同步(抢占可能在任意指令打断)简单(只在自愿点切换,无竞态)
故障影响一个死循环不致命(会被抢占)一个死循环拖垮全系统
代表Linux、Windows、macOS、现代所有通用 OS早期 Windows 3.1、Mac OS 9、协程/goroutine 调度
  • 现代通用 OS 都是抢占式——为了交互响应和避免流氓进程霸占 CPU。Linux 还支持内核抢占(kernel preemption),即使在内核态执行也能被抢占。
  • 协程/goroutine 是协作式(非抢占式)——它们在用户态调度,靠主动 yield 让出,所以一个不 yield 的协程会阻塞整个线程(Go 1.14 前 goroutine 不抢占,死循环卡死 scheduler)。

四、调度目标:公平、吞吐、响应、周转

调度器的四个目标相互冲突,没有"最优"算法,只有"针对场景权衡"的算法:

目标含义侧重谁谁优化它
公平(Fairness)每个进程都能得到 CPU,不饿死所有进程RR(绝对公平的时间片轮转)
吞吐(Throughput)单位时间完成的作业数系统整体SJF(短作业先做,单位时间完成多)
响应(Response)从输入到首响应的延迟交互用户RR(时间片保证交互进程快速被调度)
周转(Turnaround)从提交到完成的总时间批处理作业SJF(平均周转最优)
  • 公平 vs 吞吐:RR 绝对公平但频繁切换降低吞吐;SJF 高吞吐但饿死长作业(不公平)。
  • 响应 vs 周转:RR 响应快但周转长(频繁切换);SJF 周转短但响应慢(长作业前的短作业要先做完)。
  • CPU 利用率:CPU 忙碌时间占比。IO 密集型进程多时,调度器让它们用完时间片立刻去 IO,CPU 可同时跑别的——提升并发度与利用率。

五、CPU 密集型 vs IO 密集型

进程按主要消耗的资源分两类,调度策略要区别对待:

维度CPU 密集型(CPU-bound)IO 密集型(IO-bound)
主要工作算 CPU(编译、计算、编码)等 IO(键盘/网络/磁盘交互)
CPU 突发长(连续算很久)短(算一下就去 IO)
时间片偏好长一点(减少切换开销)短而频(快速响应交互)
系统角色吞吐瓶颈并发度提升者
例子编译器、科学计算、视频编码、压缩编辑器、浏览器、数据库、shell
  • IO 密集型进程是调度器的"好朋友":它们用完 CPU 立刻去等 IO,CPU 立刻可服务别的进程——系统并发度高。所以调度器倾向于优先调度 IO 密集型(如 Linux 调度器给交互进程更高优先级)。
  • 混合型:实际进程往往是 CPU/IO 混合(如数据库:查询时算 CPU、读写时等磁盘),调度器需动态判断进程当前是 CPU 突发还是 IO 突发(Linux CFS 通过统计进程睡眠时间动态调整优先级)。

下一步

理解了调度的概念、时机、抢占式/非抢占式、目标与进程类型后,下一步深入五种调度算法——调度算法详解讲透 FCFS/SJF/RR/优先级/MLFQ 的原理、优缺点与适用场景。