1️⃣ 核心结论
dispatch_async只是把任务提交到队列中,任务什么时候真正开始执行,取决于队列类型、队列中的前置任务、线程资源以及系统调度策略。
换句话说:提交 ≠ 执行。
2️⃣ 提交阶段 vs 执行阶段
提交阶段(enqueue)
DispatchQueue.global().async {
work()
}
-
系统做了什么:
- 将 block 封装成任务对象
- 放入目标队列(target queue)
- 立即返回调用线程
-
注意:
- 调用线程不等待
- 任务只在队列里“排队”
执行阶段(start execution)
任务真正开始执行取决于:
-
队列类型
- 串行队列:前面所有任务完成后才开始
- 并行队列:可以和其他任务同时开始(如果线程资源允许)
-
线程资源
- 是否有可用 worker thread
- 是否受系统 QoS / 节能策略限制
-
任务调度顺序
- FIFO / barrier / target queue 的规则
-
系统调度
- 线程可能延迟唤醒
- 系统可能对低 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 提交就立刻执行