1-10.【GCD】dispatch_async 提交的任务,什么时候“真正开始执行”?

4 阅读2分钟

1️⃣ 核心结论

dispatch_async 只是把任务提交到队列中,任务什么时候真正开始执行,取决于队列类型、队列中的前置任务、线程资源以及系统调度策略。

换句话说:提交 ≠ 执行


2️⃣ 提交阶段 vs 执行阶段

提交阶段(enqueue)

DispatchQueue.global().async {
    work()
}
  • 系统做了什么:

    1. 将 block 封装成任务对象
    2. 放入目标队列(target queue)
    3. 立即返回调用线程
  • 注意:

    • 调用线程不等待
    • 任务只在队列里“排队”

执行阶段(start execution)

任务真正开始执行取决于:

  1. 队列类型

    • 串行队列:前面所有任务完成后才开始
    • 并行队列:可以和其他任务同时开始(如果线程资源允许)
  2. 线程资源

    • 是否有可用 worker thread
    • 是否受系统 QoS / 节能策略限制
  3. 任务调度顺序

    • FIFO / barrier / target queue 的规则
  4. 系统调度

    • 线程可能延迟唤醒
    • 系统可能对低 QoS 任务降速

3️⃣ 举例说明

let serial = DispatchQueue(label: "serial")

serial.async { print("A") }
serial.async { print("B") }
  • “A” 会先执行

  • “B” 只会在 “A” 完成后才开始

  • 并且:

    • 不一定在同一线程上执行

DispatchQueue.global(qos: .background).async {
    print("background")
}
  • 任务可能:

    • 马上被分配一个 worker thread 执行
    • 也可能被延迟调度(系统负载高 / 节能模式 / 低优先级 QoS)
  • 真正开始执行的时刻由系统线程池决定


4️⃣ fast-path / lazy execution

  • 对于空闲队列 + 可用线程:

    • GCD 有“fast-path”:直接执行 block
  • 对于繁忙队列 / 串行队列:

    • block 被放入队列等待
  • 队列和线程池内部都有状态机控制何时执行


5️⃣ 与 sync 的区别

方式提交执行阻塞调用线程
async立即放队列何时资源允许
sync立即放队列当前线程可能直接执行
  • async 不保证立刻执行
  • sync 可能立即执行,也可能阻塞等待

6️⃣ 小结

  • dispatch_async 只是 enqueue

  • 真正执行:

    • 串行队列:前面任务完成
    • 并行队列:线程可用即可
    • 系统调度、QoS、RunLoop、线程池状态都会影响开始时间
  • 不要假设 async 提交就立刻执行