DispatchQueue是如何工作的?(特别是多线程)



我不了解DispatchQueue的工作原理,想了解更多关于它们如何实现基本排队理论要求的信息。我尝试使用检查队列

dump(DispatchQueue.global())

这给出了这样的输出:

- <OS_dispatch_queue_global: com.apple.root.default-qos[0x10c041f00] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}> #0
- super: OS_dispatch_queue
- super: OS_dispatch_object
- super: OS_object
- super: NSObject

我得到标签是com.apple.root.default-qos,这是在Apple文档中指定的,类是打包的OS_dispatch_queue_global。我知道qos在队列本身上是可查询的,这也是有道理的。宽度我认为只是指分配的内存大小。

我不明白的是xrefrefsref的相关性,我认为它们是队列的内部ID,但我不确定。我认为它们与基本的排队概念有关(想到了多线程),但如果能更详细地了解这一点,那就太好了。

autoreleaseFrequency是否在此调试描述中隐藏?此外,in-barrier = 0是什么意思?我尝试创建一个自定义队列,但它被in-flight = 0。。对此也感到困惑。

关于这些未记录的变量与排队理论之间的关系,有什么想法吗?我认为这些都是API的未记录的内部内容,所以任何有教育意义和合理的解释都是好的!

谢谢。

为什么要问这个问题

这是关于grand-central-dispatch内部结构的一个相当广泛的问题。我很难理解dumpED的输出,因为WWDC为GCD制作的10个视频和幻灯片已不再公开。我也不知道开源的libdispatch回购(谢谢Rob)。这不一定是个问题,但SO上没有相关的QA详细解释这个话题。

为什么选择GCD

根据WWDC的10 GCD转录本(感谢Rob),API背后的主要思想是简化与使用#selectorAPI进行多线程相关的样板。

GCD的好处

苹果发布了一个新的基于block的API,而不是使用函数指针,还启用了类型安全代码,如果块的类型签名错误,该代码不会崩溃。在函数参数、局部变量和@property声明中使用typedefs也使代码更加简洁。队列允许您将代码和某些状态捕获为一块数据,这些数据在后台自动管理、排队和执行。

同一个会话提到了GCD如何在后台管理底层线程。当需要执行块时,它将块排入队列以在线程上执行,然后当不再引用这些线程时释放这些线程(确切地说是PThread)。GCD自动管理线程,并且不公开这个API-当DispatchWorkItem退出队列时,GCD为这个块创建一个线程来执行

performSelector的缺点

performSelector:onThread:withObject:waitUntilDone:有许多缺点,这些缺点表明,对于并发、等待和同步等现代挑战,设计很差。在CCD_ 23中切换线程时导致末日金字塔。此外,NSObject.performSelector系列的线程方法是不灵活和有限的:

  1. 没有用于优化特定线程上的并发、初始非活动或同步的选项。与GCD不同
  2. 只有选择器可以分派到新线程(糟糕)
  3. 给定函数的大量线程会导致混乱的代码(末日金字塔)
  4. 不支持无限制排队(在iOS 4中宣布GCD时)NSOperationAPI。NSOperations是一个高级、详细的API,在iOS4中引入调度元素(低级API,后来成为GCD)后变得更加强大
  5. 许多错误与未处理的无效Selector错误有关(类型安全)

DispatchQueue内部构件

我相信xrefrefsref是内部寄存器,用于管理自动引用计数的引用计数。GCD在大多数情况下都会在需要时调用dispatch_retaindispatch_release,因此我们不必担心在执行完所有块后释放队列。然而,在某些情况下,开发人员可以手动调用retainrelease,以确保即使不直接使用队列也能保留。当在具有正引用计数的队列上调用release时,这些寄存器允许libDispatch崩溃,以便更好地处理错误。

当调用具有DispatchQueue.global().async或类似的块时,我相信这会增加该队列的引用计数(xrefref)。

问题中的变量没有明确记录,但我可以告诉你:

  • xref统计对一般DispatchQueue的外部引用的数量
  • CCD_ 43计数对一般CCD_ 44的引用的总数
  • sref统计对API串行/并发/运行循环队列、源和mach通道的引用数量(这些引用需要以不同的方式跟踪,因为它们使用不同的类型表示)

in-barrier看起来像一个内部状态标志(DispatchWorkItemFlag),用于跟踪是否应该调度提交到并发队列的新工作项。只有在屏障工作项完成后,队列才会返回到对屏障之后提交的工作项进行调度。in-flight表示当前没有有效的屏障。

state也没有明确记录,但我认为它指向内存,在内存中,块可以访问块调度范围中的变量。

相关内容

  • 没有找到相关文章

最新更新