操作系统中的进程调度算法:多处理器调度(Multiprocessor Scheduling)
字数 1674 2025-11-26 13:08:48
操作系统中的进程调度算法:多处理器调度(Multiprocessor Scheduling)
1. 问题背景
在多核或多处理器系统中,多个CPU核心可同时执行进程,这要求调度算法不仅考虑进程优先级和公平性,还需解决负载均衡、缓存亲和性和同步开销等新问题。单核调度算法(如CFS、RR)直接应用于多处理器环境可能导致性能下降。
2. 多处理器调度的核心挑战
-
负载均衡(Load Balancing)
- 问题:若某些CPU空闲而其他CPU过载,系统整体效率降低。
- 解决:需动态将进程从繁忙CPU迁移到空闲CPU。
- 难点:迁移可能破坏缓存局部性(如进程数据在原CPU缓存中)。
-
缓存亲和性(Cache Affinity)
- 定义:进程在同一个CPU上运行时,可复用其缓存数据,减少访问内存的延迟。
- 冲突:负载均衡可能强制进程迁移,导致缓存失效,增加延迟。
-
同步开销(Synchronization Overhead)
- 多CPU同时访问调度队列可能需加锁,引发竞争(如自旋锁消耗CPU周期)。
-
异构性(Heterogeneity)
- 如大小核架构(ARM big.LITTLE),需区分CPU计算能力,将重任务分配到大核。
3. 多处理器调度策略分类
3.1 对称多处理器调度(SMP Scheduling)
所有CPU共享同一内存和调度队列,常见策略:
-
全局队列(Global Queue)
- 所有待运行进程存入一个全局队列,由多个CPU竞争加锁后选取进程。
- 优点:自动实现负载均衡。
- 缺点:锁竞争可能成为瓶颈(CPU越多竞争越激烈)。
-
局部队列(Per-CPU Queue)
- 每个CPU维护独立的进程队列,避免全局锁竞争。
- 优点:减少同步开销,增强缓存亲和性。
- 缺点:可能负载不均,需定期负载均衡(如Linux的
migration线程)。
3.2 负载均衡实现
- 推送模式(Push Migration)
空闲CPU主动从繁忙CPU“拉取”进程,或由系统监控线程(如Linux的load_balance())定期迁移进程。 - 拉取模式(Pull Migration)
繁忙CPU将多余进程“推送”到空闲CPU的队列。
3.3 亲和性优化
- 调度域(Scheduling Domains)
将CPU按物理位置分组(如同一NUMA节点),优先在域内迁移进程,减少跨节点内存访问延迟。 - 软亲和性(Soft Affinity)
调度器尽量将进程分配到上次运行的CPU,但允许迁移以平衡负载。 - 硬亲和性(Hard Affinity)
通过系统调用(如Linux的sched_setaffinity())绑定进程到特定CPU,避免迁移但可能破坏均衡。
3.4 异构调度(Heterogeneous Scheduling)
- 如Android的HMP调度器:
- 区分大核(高性能)和小核(低功耗)。
- 计算密集型任务分配到大核,后台任务分配到小核。
- 动态根据负载调整任务位置(如将活跃进程迁移到大核)。
4. 实例:Linux的多处理器调度
-
CFS(Completely Fair Scheduler)的扩展
- 每个CPU维护一个
cfs_rq(CFS运行队列),通过load_balance()定期均衡负载。 - 使用调度域层次结构(NUMA→物理CPU→核心→超线程)优化迁移范围。
- 每个CPU维护一个
-
唤醒进程时的优化
- 进程被唤醒时(如I/O完成),优先放到原CPU的队列(缓存亲和性)。
- 若原CPU繁忙,检查空闲CPU,选择拓扑最近(如共享L2缓存)的CPU迁移。
5. 总结与面试要点
- 关键权衡:负载均衡与缓存亲和性的矛盾。
- 设计原则:
- 减少锁竞争(如局部队列+负载均衡)。
- 利用硬件拓扑(调度域)降低迁移成本。
- 异构系统需区分CPU能力。
- 扩展问题:
- “如何避免多处理器调度中的锁竞争?”
- 答:使用无锁数据结构或分层队列(如Linux的每CPU队列)。
- “NUMA架构下调度要注意什么?”
- 答:优先在NUMA节点内迁移,避免远程内存访问。
- “如何避免多处理器调度中的锁竞争?”