You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS/Swift中DispatchQueue并发测试不符预期,主队列执行顺序存疑

关于GCD主队列异步任务执行顺序与QoS的疑问解答

首先来解答你第一个核心疑问:为什么主队列的Main输出会排在最后?

你可能混淆了队列优先级和主队列的执行机制。主队列确实和主线程绑定,且本身属于高优先级队列,但它有个关键特性:主队列的异步任务不会抢占当前正在主线程运行的代码。

在你的第一段代码里,当调用DispatchQueue.main.async时,这个任务只是被添加到了主队列的末尾,但此时主线程正忙着执行Playground里的同步代码(比如导入框架、设置needsIndefiniteExecution、以及其他几个async调用的逻辑)。只有当主线程当前所有同步执行的代码都完成后,Runloop才会去处理主队列里等待的任务——哪怕主队列QoS优先级很高,也得等主线程当前的工作做完,所以Main的五次打印才会排在最后。

你理解的User Interactive和Background输出顺序随机是对的:不同QoS的全局队列优先级有差异,但系统调度线程时会根据当前负载等情况动态调整,高优先级任务只是有更高的执行概率,并非每次都严格按优先级顺序完成。

再看你补充的代码:

print("BEGINNING OF CODE")
DispatchQueue.main.async {
    for _ in 1...5 {
        print("Main")
    }
}
DispatchQueue.global().sync {
    for _ in 1...5 {
        print("Sync Global")
    }
}
DispatchQueue.global(qos: .background).async {
    for _ in 1...5 {
        print("Background")
    }
}
DispatchQueue.global(qos: .userInteractive).async {
    for _ in 1...5 {
        print("User Interactive")
    }
}
print("END OF CODE")

对应的输出:

BEGINNING OF CODE
Sync Global
Sync Global
Sync Global
Sync Global
Sync Global
END OF CODE
User Interactive
Background
User Interactive
User Interactive
User Interactive
User ...

这里的关键点是sync调用的行为:sync会阻塞当前调用线程(也就是主线程),直到这个同步任务执行完成。所以当你调用DispatchQueue.global().sync时,主线程会立刻暂停当前代码执行,转而等待这个全局队列的任务完成——也就是先打印五次Sync Global,之后才会继续执行后面的async调用和print("END OF CODE")。

同样,主队列的Main任务还是要等主线程当前所有同步代码(从BEGINNING到END OF CODE的所有逻辑)执行完毕,才会被Runloop处理,所以它的打印会在所有异步任务之后(如果你的输出没写完,最后应该能看到Main的五次打印)。

最后总结几个核心知识点:

  • 主队列的异步任务必须等待主线程当前Runloop周期内的任务全部完成,才会开始执行
  • sync调用会阻塞当前线程,必须等任务完成才会继续后续代码
  • QoS优先级影响的是系统调度线程的概率,但主队列的执行时机和QoS无关,只和主线程的空闲状态有关

内容的提问来源于stack exchange,提问作者Michael Hsu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:44:17