Swift:DispatchQueue.global(qos: .userInitiated).async 是否锁定了主



我目前正在尝试解决0x8BADF00D

faultingThread是 0,我想这是主线程。但是,我不认为我正在做的大量工作实际上在主线程中下降。

在我做的在主线程上运行的函数中

DispatchQueue.global(qos: .userInitiated).async {
// ... heavy work
// and after the work is done I do
DispatchQueue.main.asyncAfter(deadline: .now()+1.0) {
// ... displaying heavy work
}
}

我的逻辑有明显的错误吗?我以为 .userInitiated 会离开主线程,尤其是在.async上。

"exception" : {"codes":"0x0000000000000000,0x0000000000000000","rawCodes":[0,0],"type":"EXC_CRASH","signal":"SIGKILL"}, "终止" : {"flags":6,"code":2343432205,"namespace":"FRONTBOARD","reason":["<RBSTerminateContext|>:579 耗尽实际(挂钟)时间允许 10.00 秒","进程可见性: 背景","进程状态: 正在运行","监视器事件: 场景更新","看门狗可见性:背景","看门狗CPU静态:(","经过的总CPU时间(秒):21.740(用户21.740,系统0.000),99%CPU",","经过的应用程序CPU时间(秒):9.832,45%CPU",") 报告类型:崩溃日志最大终止电阻:交互式>"]}, "错误线程" : 0,

这里的模式是正确的(尽管建议使用更合理的QoS)。您的看门狗问题(主线程被阻塞)位于其他地方。但是,将昂贵的进程调度到后台队列,然后将 UI/模型更新调度回主队列是正确的过程。


注意:在某些情况下,此常规模式可能会阻塞主线程。具体来说,如果你有线程爆炸(例如,超过64个任务调度到该全局队列),则可以阻塞/死锁。GCD 的线程池非常有限(此时为 64 个),如果超过此值,后续调度到该队列的尝试将阻塞,直到队列被释放。这通常只是在使用锁、信号量或以其他方式等待时的问题。不幸的是,您的代码片段中没有足够的内容供我们诊断这种特殊情况下的问题。

因此,如果出现线程爆炸,则应重构以限制最大并发程度。操作队列maxConcurrentOperation来促进这一点。GCD 的concurrentPerform不会超过在任何给定时间允许运行的最大线程数。Swift 5.5 协作线程池也将并行性限制在合理的限制内。Combine 具有"最大发布者"来控制并发程度。过去,我们可能使用非零信号量来限制并发程度(尽管现在我们倾向于使用上述当代解决方案之一)。有很多方法可以缓解线程爆炸。

所有这些都假设问题在于线程爆炸(如果嵌套的async调度阻塞,这可能是罪魁祸首)。如果你没有线程爆炸,那么你只是有其他东西,完全不相关,阻塞了主线程。

QoS 确定系统仅计划执行任务的优先级。

您可以随时使用Thread.current检查当前线程:

DispatchQueue.global(qos: .userInitiated).async {
print(Thread.current.description)
}

输出:

<NSThread: 0x6000005bde00>{number = 7, name = (null)}`

主线程只有number = 0name = main,因此您的代码在后台线程上运行,您可以对其进行繁重的工作。

最新更新