1-25.【GCD】QoS 是如何发生“继承”的?

0 阅读2分钟

1️⃣ 核心结论

QoS 继承是指当一个任务提交到队列时,如果提交线程的 QoS 高于目标队列任务的 QoS,系统会临时提升队列任务的 QoS,保证高优先级任务不会被低优先级任务阻塞。

  • 本质:防止高优先级任务被低优先级队列拖慢 → 保证响应性
  • 临时提升仅在调度时生效,任务完成后恢复队列默认 QoS

2️⃣ QoS 继承机制

2.1 什么时候继承

  • 当高 QoS 线程 dispatch_asyncsync 提交任务到 低 QoS 队列

  • 系统检测:

    • 任务提交线程 QoS > 队列 QoS
    • 临时提升任务 QoS 到提交线程 QoS
  • 执行完毕后:

    • 队列恢复原本的 QoS

2.2 技术原理

  • GCD 每个队列维护 默认 QoS
  • 任务提交时会有 effective QoS = max(队列 QoS, 提交线程 QoS)
  • 调度时线程池会优先调度 effective QoS 高的任务

3️⃣ 真实场景示例

假设有一个后台队列处理下载任务,但 UI 有高优先级任务触发:

// 后台队列(低 QoS)
let backgroundQueue = DispatchQueue(label: "backgroundQueue", qos: .background)

// UI 高优先级线程
DispatchQueue.global(qos: .userInitiated).async {
    print("用户触发操作")
    
    // 提交任务到后台队列
    backgroundQueue.async {
        print("后台下载任务处理用户请求")
    }
}

解释

  1. 用户在主线程或 .userInitiated 队列触发事件
  2. 背景队列默认 QoS = .background
  3. 提交任务到后台队列时,GCD 会 临时提升这个任务的 QoS 为 .userInitiated
  4. 系统优先调度此任务,避免高优先级 UI 被阻塞
  5. 任务完成后,队列恢复原本 QoS

✅ 效果:高优先级用户请求不会被后台低 QoS 队列拖慢


4️⃣ 常见使用场景

  1. UI 操作触发后台任务

    • 用户点击按钮触发后台数据处理
    • 确保处理及时,不被后台低 QoS 任务阻塞
  2. 链式异步任务

    • 高 QoS 任务在串行队列中触发多个 async
    • 后续任务会继承 QoS,保持优先级
  3. 全局队列的 QoS 提升

    • 提交到 .utility.background 全局队列
    • 高 QoS 提交线程 → 临时提升任务 QoS

5️⃣ 总结

  • QoS 继承 = 任务优先级保护机制
  • 避免高优先级任务被低优先级队列拖慢
  • 在 GCD 中,实际任务执行的 QoS = max(队列 QoS, 提交线程 QoS)
  • 临时提升,只影响调度,不改变队列默认 QoS