Lec 11 调度

Lec 11 处理器调度

License

本内容版权归上海交通大学并行与分布式系统研究所所有
使用者可以将全部或部分本内容免费用于非商业用途
使用者在使用全部或部分本内容时请注明来源
资料来自上海交通大学并行与分布式系统研究所+材料名字
对于不遵守此声明或者其他违法使用本内容者,将依法保留追究权
本内容的发布采用 Creative Commons Attribution 4.0 License
完整文本

1 处理器调度

  • 系统中的任务(线程,单线程进程)多于处理器数目
  • 对象:CPU执行的最小单元,可以是进程或线程,统一用“任务”描述。

img

  • 决策:

    1. 下一个执行的任务
    2. 执行该任务的CPU
    3. 执行的时长
  • 时机:

    1. 执行时间用尽
    2. 等待I/O请求
    3. 睡眠
    4. 中断

1.1 什么是调度?

  • 协调请求对于资源的使用。
  • 不同场景下具有不同的调度指标。
    • 批处理系统:高吞吐量。
    • 交互式系统:低响应时间。
    • 网络服务器:可扩展性。
    • 移动设备:低能耗。
    • 实时系统:实时性
  • 共有的目标:高资源利用率,多任务公*性,低调度开销。

1.2 常用调度指标

  • 降低周转时间:任务第一次进入系统到执行结束的时间
  • 降低响应时间:任务第一次进入系统到第一次给用户输出的时间
  • 实时性:在任务的截止时间内完成任务
  • 公*性:每个任务都应该有机会执行,不能饿死
  • 开销低:调度器是为了优化系统,而非制造性能BUG
  • 可扩展:随着任务数量增加,仍能正常工作

1.3 调度面临挑战

  • 缺少信息(没有先知)
    • 工作场景动态变化
  • 任务间的复杂交互
  • 调度目标多样性
    • 不同的系统可能关注不一样的调度指标
  • 许多方面存在取舍
    • 调度开销 V.S. 调度效果
    • 优先级 V.S. 公*
    • 能耗 V.S. 性能

1.4 Linux中的调度策略

  • 为了满足不同需求提供多种调度策略
  • 以Linux两种调度器为例,每种对应多个调度策略
    • 完全公*调度器(CFS, Complete Fair)
      • SCHED_OTHER
      • SCHED_BATCH
      • SCHED_IDLE
    • 实时调度器(RT, Real Time)
      • SCHED_FIFO
      • SCHED_RR

img

img

2 经典调度

2.1 先到先得

  • 简单,直观。
  • *均周转,响应时间过长。

img

2.2 短任务优先

  • *均周转时间短
  • 不公*,任务饿死。*均响应时间过长。

img

2.3 抢占式调度(Preemptive Scheduling)

  • 每次任务执行
    • 一定时间后被切换到下一任务
    • 并非执行到终止
  • 通过定时触发的时钟中断实现

2.4 Round Robin(时间片轮转)

  • 轮询:公*,*均响应时间短
  • 牺牲了周转时间。

img

  • 当每个任务执行时间差不多时,周转时间问题会很明显。
  • 时间片过长,退化成“先到先得”。
  • 时间片过短,调度时间开销会变大。

3 优先级调度

3.1 调度优先级

  • 操作系统中任务是不同的。例如系统/用户,前台/后台。
  • 不加以区分有可能导致关键任务无法及时处理,导致缓慢或错误
  • 确保重要的任务优先调度

3.2 多级队列(Multi-Level Queue, MLQ)

  • 维护多个队列并设置对应优先级。
  • 队列间采取优先级调度。高优先级先行。
  • 队列内采取round robin或其他公*/*似公*调度策略。
优先级如何选取
  • 什么样的任务应该有高优先级?
    • I/O密集型任务
      • 为了更高的资源利用率
    • 用户主动设置的重要任务
    • 时延要求极高(必须在短时间内完成)的任务

本质上,先到先得和最短任务优先都是优先级调度策略。时间片轮转是优先级全部相同的优先级策略。

3.3 Linux 实时调度器

  • Linux Real-Time Scheduler,使用Multi-level Queue优先级调度
  • 每个任务有自己的优先级、具体策略
  • 具体策略可根据任务需求针对性选择
    • SCHED_RR:任务执行一定时间片后挂起
    • SCHED_FIFO:任务执行至结束
    • SCHED_OTHER为完全公*调度。

3.4 优先级动态调整

  • 操作系统中的工作场景是动态变化的

  • 静态设置的优先级可能导致

  • 资源利用率低

    • 一个CPU密集型动态转变为I/O密集型任务
  • 优先级反转

  • 某些场景下,任务的优先级需要动态调整

饥饿(低优先级)

img

  • 目前存在的调度策略限制:
  • 周转时间、响应时间过长
    • 先到先得
  • 依赖对于任务的先验知识
    • 预知任务执行时间:最短任务优先
    • 预知任务是否为I/O密集型任务:多级队列(设置优先级)
  • 假设调度没有开销
    • RR(将时间片设置过短会导致调度开销过大)

3.5 解决:多级反馈队列(MLFQ)

  • 一个无需先验知识的通用调度策略

    • 周转时间低、响应时间低
    • 调度开销低
  • 通过动态分析任务运行历史,总结任务特征

    • 类似思想的体现:分支预测、缓存
    • 需要注意:如果工作场景变化频繁,效果会很差
基本算法
  • 规则 1:

    • 优先级高的任务会抢占优先级低的任务
  • 规则 2:

    • 每个任务会被分配时间片,优先级相同的两个任务使用时间片轮转
  • 规则 3:

    • 任务被创建时,假设该任务是短任务,为它分配最高优先级
  • 规则 4a:

    • 一个任务时间片耗尽后,它的优先级会被降低一级
  • 规则 4b:

    • 如果一个任务在时间片耗尽前放弃CPU,那么它的优先级不变
    • 任务重新执行时,会被分配新的时间片
  • 更改规则4a,规则4b。规则4:

    • 一个任务时间片耗尽后(无论它期间放弃了多次CPU,它的时间片不会被重置),它的优先级会被降低一级
  • MLFQ在该规则下:

    • 记录每个任务在当前优先级使用的时间片
    • 当累计一个完整时间片被用完后,降低其优先级
  • 规则 5

    • 在某个时间段S后,将系统中所有任务优先级升为最高
  • 针对混合工作场景

    • 执行时间短的任务
      • 交互式任务
      • I/O密集型任务
  • 执行时间长的任务

    • CPU密集型计算任务

img
img

基本算法(规则1-规则4b)存在问题一
  • 长任务饥饿

    • 过多的短任务、I/O密集型任务可能占用所有CPU时间
  • 任务特征可能动态变化

    • CPU密集型任务变成了交互式任务等
  • 规则 5:

    • 在某个时间段S后,将系统中所有任务优先级升为最高
  • 避免长任务饿死

    • 所有任务的优先级会定时地提升最高
    • 最高级队列采用RR,长任务一定会被调度到
  • 针对任务特征动态变化的场景

    • MLFQ会定时地重新审视每个任务

img

基本算法(规则1-5)存在问题二
  • 无法应对抢占CPU时间的攻击
    • 恶意任务在时间片用完前发起I/O请求
    • 避免MLFQ将该任务的优先级降低,并且每次重新执行时间片会被重置
      • 几乎独占CPU!

更改规则4如下:

  • 更改规则4a,规则4b。规则4:
    • 一个任务时间片耗尽后(无论它期间放弃了多次CPU,它的时间片不会被重置),它的优先级会被降低一级
  • MLFQ在该规则下:
    • 记录每个任务在当前优先级使用的时间片
    • 当累计一个完整时间片被用完后,降低其优先级

img

参数调试
  • 如何确定MLFQ的各种参数?

    • 优先级队列的数量
    • 不同队列的时间片长短
    • 定时优先级提升的时间间隔
  • 每个参数都体现了MLFQ的权衡

    • 对于不同的工作场景,不同的参数会导致不一样的表现
  • 为不同队列选择不同的时间片

    • 高优先级队列时间片较短,针对短任务
      • 提升响应时间
    • 低优先级队列时间片较长,针对长任务
      • 降低调度开销
小结
  • Multi-Level Feedback Queue 多级反馈队列
    • 通过观察任务的历史执行,动态确定任务优先级
      • 无需任务的先验知识
    • 同时达到了周转时间和响应时间两方面的要求
      • 对于短任务,周转时间指标*似于最短工作时间优先。
      • 对于交互式任务,响应时间指标*似于时间片轮转。
    • 可以避免长任务的饿死
  • 许多著名系统的调度器是基于多级反馈队列实现的
    • BSD, Solaris, Windows NT 和后续Windows操作系统

3.6 高响应比优先:短任务优先执行,防止长任务饥饿

响应比(Response Ratio)是一个任务的响应时间与运行时间的比值。

img

结合了先到先得和最短工作时间优先的策略,避免了后者的公*性问题。

4 公*共享调度

4.1 公*共享

  • 每个用户占用的资源是成比例的

    • 而非被任务的数量决定
  • 每个用户占用的资源是可以被计算的

    • 设定“份额"以确定相对比例(绝对值不重要)
    • 例:份额为4的用户使用资源,是份额为2的用户的2倍

img
img

4.2 彩票调度(Lottery Scheduling)

  • 每次调度时生成随机数 R[0,T).
  • 根据生成的随机数找到对应的任务。
  • 原理就是调度T次时,每个任务被调度次数的期望==该任务的份额
彩票转让
  • 场景:
    • 在通信过程中,客户端需要等到服务端返回才能继续执行
  • 客户端将自己所有的ticket转让给服务端
    • 确保服务端可以尽可能使用更多资源,迅速处理
  • 同样适用于其他需要同步的场景

img

  • 份额影响任务对CPU的占用比例

    • 不会有任务饿死
  • 优先级影响任务对CPU的使用顺序

    • 可能产生饿死
  • 随机的好处是?

    • 简单
  • 随机带来的问题是?

    • 不精确——伪随机非真随机
    • 各个任务对CPU时间的占比会有误差

4.3 步幅调度(stride scheduling)

  • 确定性版本的Lottery Scheduling
    • 可以沿用tickets的概念

Stride——步幅,任务一次执行增加的虚拟时间.

  • 步幅=最大步幅份额
    • 最大步幅是一个足够大的整数
    • 可以将其设为所有份额的最小公倍数
  • Pass:累计执行的虚拟时间

img

img

4.4 Linux完全公*调度器

CFS同样采用了公*共享的思想,其vruntime 等价于步幅调度的pass。

  • CFS达成公*共享的方式
    • 通过调整任务每次执行的时间

img

  • 假设份额为ticket的任务某次执行了T单位时间,应该如何更新其虚拟时间?
  • 步幅调度更新虚拟时间的方式:
    • 累计执行虚拟时间+=T
    • vruntime+=T

4.5 虚拟时间对调度行为的影响

  • 虚拟时间的意义
    • 虚拟时间相对大小,对应了任务的优先级
    • 虚拟时间的绝对值,对应了任务预期占用CPU的时间长度
  • 如果新创建、刚被唤醒的任务vruntime很小,可能遇到的问题是?
    • 这些新创建、刚被唤醒的任务会立即长时间占用CPU
  • CFS当前的解决方案
    • 维护所有任务虚拟时间的最小值min_vruntime
    • 当任务被创建、唤醒时,保证任务的vruntime不小于min_vruntime

5 多核调度策略

  • 一个进程的不同线程可以在不同的CPU上同时进行
  • 可能导致的问题:
    • 所有CPU竞争全局调度器
    • 同一个线程可能在不同CPU上切换
      • 切换开销大:Cache、TLB、…
      • 缓存局部性差

img

  • 制定线程在CPU上执行会出现负载不均衡的问题。
  • 需要追踪CPU负载情况,进行迁移。
  • 根据任务负载定义的不同,负载均衡的效果也不尽相同
  • 每个CPU核心本地运行队列的长度
    • 优势:实现简单
    • 劣势:不能准确反应当前CPU的负载情况
  • 每个任务单位时间内使用的CPU资源
    • 优势:直观反映当前CPU的负载情况
    • 劣势:引入额外负载追踪开销

亲和性(Affinity)

  • 程序员如何控制自己程序的行为?
    • 例如,他希望某个线程独占一个CPU核心
  • 通过操作系统暴露的任务亲和性接口,可以指定任务能够使用的CPU核心

img

cpu_set_t为指定目标CPU集合的bitmask

总结

调度指标,策略 V.S. 机制,经典调度,优先级调度,公*共享调度,多核调度

posted @   木木ちゃん  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示