DispatchQueue.global(qos: .userInteractive).async和DispatchQueue.main.async相同吗?

70
5个回答

38

这里介绍了“服务质量”定义:

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

看起来,“主”线程的服务质量类别是“用户交互”。然而,仅因为一个线程被创建时带有“用户交互”的服务质量并不意味着它就是“主”线程。

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

通常情况下,主线程被认为是特殊线程,在此线程上执行所有与视图相关的访问操作。如果某个操作需要消耗大量时间,例如调用 Web 服务、压缩文件等,你应该在单独的队列中运行代码,并在处理完成后返回到主队列以更新用户界面。

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


1
我尝试了断点实验...它显示了不同的线程... 但我在Stackoverflow上看到了这篇文章... https://dev59.com/pVcP5IYBdhLWcg3wf58G#44324968在这里,也有人写道两者是相同的。 - Nishu_Priya
@NishuPriya 根据你已经进行的实验,那个人显然是错的。有什么争议吗? - Charles Srstka
是的,Daniel和Nishu Priya是正确的,请查看https://dev59.com/pVcP5IYBdhLWcg3wf58G#44324968和https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html。 - bcr
1
在https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html 上也提到:“主线程根据其环境自动分配 QoS。在应用中,主线程运行的 QoS 等级为 user-interactive。在 XPC 服务中,主线程运行的 QoS 为 default。要检索主线程的 QoS,请调用 qos_class_main 函数,如清单4-6所示。” - He Yifei 何一非

18

它们不是相同的。它们意义不同,您应该使用您所要表达的那个。主队列是userInteractive,但并不是每个userInteractive队列都是主队列。这在苹果的GCD高效构建响应性应用中有很好的讨论。

在userInteractive级别上运行多个队列是有效的。如果您需要同时利用多个核心执行计算以保持平滑的用户交互(通常是某种动画),则可以这样做。这很少需要,并且应该小心地处理,但如果您需要同时在主线程上计算并在另一个核心上计算以跟上用户操作,那就是它的用途。

但是只能有一个主队列。它碰巧是userInteractive,但这不是它的重点。大多数UIKit不是线程安全的,仅在主队列上访问这些类才有效,而不仅仅是任何userInteractive队列。

队列优先级比它们首次出现的样子更加复杂。它们可以从队列传播到队列,以至于“低优先级”队列可能会暂时具有高优先级状态。苹果调整了这个功能的工作方式,使整个系统更具响应性。这就是为什么始终表达您的意思而不是依赖于关于内部工作方式的假设如此重要。即使您的测试向您展示两个队列始终相同,也不足以知道它们在所有设备上或将来的操作系统版本中是否相同。


12

.userInitiated 全局队列是主线程的人是错误的。它是一个非常高优先级的后台队列,但它是一个后台队列(而且它是并发的,不像主线程)。

苹果自己的示例代码和评论让这个问题非常清晰:

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

这无疑证明了苹果相信.userInitiated全局队列是“后台队列”,而不是“主线程”。


24
这个帖子特别讨论的是"userinteractive"而不是"userInitiated"。没有人说"userInitiated"在主线程上运行。用户的问题与"userinteractive"的质量服务有关。 - fnw1989

6
您可以使用 DispatchQueue.global(qos: .userInteractive).async{} 在用户与您的应用程序交互时快速在后台执行某些操作。这很少使用,因为它必须非常快地发生,所以您可能可以直接在主队列中执行它。您可以查看此讲座,其中这个问题被相当清楚地解释了。

-1

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

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

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

   •   DISPATCH_QUEUE_PRIORITY_HIGH
   •   DISPATCH_QUEUE_PRIORITY_DEFAULT
   •   DISPATCH_QUEUE_PRIORITY_LOW

提交到高优先级全局队列的块将在提交到默认或低优先级全局队列之前被调用。只有在默认或高优先级队列上没有待处理块时,才会调用提交到低优先级全局队列的块。
因此,它们是在后台线程上运行的队列,只要它们可用就会运行。它们是“非FIFO”的,因此不能保证顺序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接