DispatchQueue.global(qos: .userInteractive).async 是不是与 DispatchQueue.main.async 相同

Posted

技术标签:

【中文标题】DispatchQueue.global(qos: .userInteractive).async 是不是与 DispatchQueue.main.async 相同【英文标题】:Is DispatchQueue.global(qos: .userInteractive).async same as DispatchQueue.main.asyncDispatchQueue.global(qos: .userInteractive).async 是否与 DispatchQueue.main.async 相同 【发布时间】:2018-02-05 08:11:41 【问题描述】:

我正在阅读教程: https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1

并遇到了 QoS 类用户交互的定义。 它在那里提到这应该在主线程上运行。 所以,我的问题是

DispatchQueue.global(qos: .userInteractive).async 

DispatchQueue.main.async

谢谢!!

【问题讨论】:

【参考方案1】:

这里描述了“服务质量”的定义:

https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-ios/PrioritizeWorkWithQoS.html

看起来“主”线程将具有“用户交互”的 QoS 类。然而,仅仅因为一个线程是使用“用户交互”的 QoS 创建的,并不意味着它是“主”线程。

您可以在 Xcode 调试器中观察到这一点。在异步块内放置一个断点并查看 Debug Navigator 活动线程面板。从主线程调用DispatchQueue.global(qos: .userInteractive).async 时,它显示的名称与主线程不同。

一般来说,主线程被认为是应该执行所有与视图相关的访问的特殊线程。如果某事会消耗大量时间,例如调用 Web 服务、压缩文件等,您将需要在单独的队列中运行代码,当该过程完成时,返回到更新用户界面的主队列。

另请注意,在 iOS 11 中使用 Xcode 9 时,当从非主线程访问用户界面对象时会发出警告。

【讨论】:

我尝试了断点实验...它显示了不同的线程...但是我在 *** 中看到了这篇文章..***.com/questions/44324595/… 这里也有人写道两者是相同的。 @NishuPriya 根据你已经做过的实验,那个人显然是错的。有什么争议? 是的 Daniel 和 Nishu Priya 是正确的,请查看 ***.com/questions/44324595/… 和 developer.apple.com/library/content/documentation/Performance/… 在developer.apple.com/library/content/documentation/Performance/…上,还说“主线程根据其环境自动分配QoS。在应用程序中,主线程运行在用户交互的QoS级别。在XPC 服务,主线程以默认的 QoS 运行。要检索主线程的 QoS,请调用 qos_class_main 函数,如清单 4-6 所示。"【参考方案2】:

这些不一样。它们意味着不同的东西,你应该使用你想要的东西。主队列是 userInteractive,但不是每个 userInteractive 队列都是主队列。 Apple 在Building Responsive and Efficient Apps with GCD 中对此进行了很好的讨论。

在 userInteractive 级别运行多个队列是有效的。如果您需要同时使用多个内核来执行为了保持流畅的用户交互(通常是某种动画)所需的计算,这是合适的。这很少需要,应该小心完成,但如果您需要在主线程上计算某些内容,同时还要在另一个内核上计算某些内容以跟上用户操作,那就是它的用途。

但只能有一个主队列。它恰好是 userInteractive,但这不是重点。大多数 UIKit 都不是线程安全的,它只能访问主队列上的那些类,而不是任何 userInteractive 队列。

队列优先级更复杂,它们最初出现。它们可以在队列之间传播,因此“低优先级”队列可能暂时具有高优先级状态。 Apple 对它的工作方式进行了很多调整,以使整个系统更具响应性。这就是为什么总是表达你的意思如此重要,而不是依赖于事情在幕后如何运作的假设。即使您的测试表明两个队列总是相同的,也不足以知道它们在所有设备上或未来版本的操作系统上都是相同的。

【讨论】:

【参考方案3】:

任何说.userInitiated 全局队列是主线程的人都是错误的。这是一个优先级很高的后台队列,但它是一个后台队列(它是并发的,不像主线程)。

Apple 自己的sample code and comments 把事情说得很清楚:

// This handler gets called on the main thread; dispatch to a background queue for processing.
DispatchQueue.global(qos: .userInitiated).async 

这无疑证明了 Apple 认为 .userInitiated 全局队列是“后台队列”而不是“主线程”。

【讨论】:

这个线程专门讨论“userinteractive”而不是 userInitiated。没有人说 userInitiated 在主线程上。用户的问题具体与用户交互的qos有关【参考方案4】:

当您想在用户与您的应用交互时在后台快速执行某项操作时,您可以使用DispatchQueue.global(qos: .userInteractive).async。这很少使用,因为它必须发生得如此之快,您可能可以直接在主队列中进行。

您可以查看lecture,此问题已得到非常清楚的解释。

【讨论】:

【参考方案5】:

主队列确实像你说的那样在主线程上运行。

全局队列是并发队列,来自dispatch_get_global_queue的主页:

与使用 dispatch_queue_create() 分配的主队列不同,全局并发队列会在线程可用时立即调度块(“非 FIFO”完成顺序)。全局并发队列代表三个优先级:

   •   DISPATCH_QUEUE_PRIORITY_HIGH
   •   DISPATCH_QUEUE_PRIORITY_DEFAULT
   •   DISPATCH_QUEUE_PRIORITY_LOW

提交到高优先级全局队列的块将在提交到默认或低优先级全局队列的块之前被调用。只有在默认或高优先级队列上没有待处理的块时,才会调用提交到低优先级全局队列的块。

因此,它们是在可用时在后台线程上运行的队列。它们是“非先进先出”,因此无法保证订购。

【讨论】:

以上是关于DispatchQueue.global(qos: .userInteractive).async 是不是与 DispatchQueue.main.async 相同的主要内容,如果未能解决你的问题,请参考以下文章

Swift:使用DispatchQueue.global(qos:.userInitiated).asyncAfter]重复返回的结果

Swift - 内部有后台线程的退出功能

`DispatchQueue.global().async` 是不是会创建新的全局队列?

Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`

如何仅在一个线程上运行任务? [复制]

我的双重关闭功能不起作用