GCD 全局队列任务在主线程上运行
Posted
技术标签:
【中文标题】GCD 全局队列任务在主线程上运行【英文标题】:GCD global queue task run on main thread 【发布时间】:2021-11-17 14:58:26 【问题描述】:以下代码
DispatchQueue.main.async
print(Thread.current)
DispatchQueue.global().sync
print(Thread.current)
打印
<_NSMainThread: 0x60000059c140>number = 1, name = main
<_NSMainThread: 0x60000059c140>number = 1, name = main
从技术上讲,全局队列会找到一个空闲线程来运行任务,这可能是主线程。
是否有明确的规则表明添加到全局队列的任务何时在主线程上执行?
所以放在全局队列中的耗时任务不会影响主线程。
【问题讨论】:
【参考方案1】:同步任务将阻塞您的调用线程,这是您代码中的主线程。
即使全局队列中的任务被分派到全局线程而不是主线程。主线程仍然需要等待任务完成。
在这种情况下,GCD 会自动优化同步调度,使任务在调用线程上执行,而不是让调用线程等待。
【讨论】:
【参考方案2】:你说:
从技术上讲,全局队列会找到一个空闲线程来运行任务,这可能是主线程。
通常全局队列从工作线程池中选择一个具有适当服务质量的线程。在抓取工作线程时,它可能不会只是随机抓取主线程。它仅从其工作线程池中进行选择。
您在这里看到的是对同步调用(但不是异步调用)的非常具体的优化。作为sync
docs say:
作为性能优化,[
sync
] 尽可能在当前线程上执行块,...
这种优化可以通过同步调用实现,因为无论如何,当前线程将在同步调度期间被阻塞。因此 GCD 可以避免不需要/不需要的代价高昂的上下文切换。这是一个巧妙的小优化。
那么,什么时候不采用前面提到的性能优化呢?以上documentation引用继续:
...有一个例外:提交到主调度队列的块总是在主线程上运行。
因此,如果您执行与示例相反的操作(即,从后台队列同步调度到主队列,或使用主队列作为其最终“目标”的任何队列),优化将被关闭,并且无论如何,都会将上下文切换到主线程。它必须这样做,因为在主线程上必须发生某些 API 调用等,因此在这种情况下禁用了优化。
还有其他一些记录较少的场景可能无法使用此优化。建议不要过度依赖这种优化。请放心,当 GCD 可以时,它会尝试避免同步分派任务的代价高昂的上下文切换。
【讨论】:
以上是关于GCD 全局队列任务在主线程上运行的主要内容,如果未能解决你的问题,请参考以下文章