我不了解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
在队列本身上是可查询的,这也是有道理的。宽度我认为只是指分配的内存大小。
我不明白的是xref
、ref
和sref
的相关性,我认为它们是队列的内部ID,但我不确定。我认为它们与基本的排队概念有关(想到了多线程),但如果能更详细地了解这一点,那就太好了。
autoreleaseFrequency
是否在此调试描述中隐藏?此外,in-barrier = 0
是什么意思?我尝试创建一个自定义队列,但它被in-flight = 0
。。对此也感到困惑。
关于这些未记录的变量与排队理论之间的关系,有什么想法吗?我认为这些都是API的未记录的内部内容,所以任何有教育意义和合理的解释都是好的!
谢谢。
为什么要问这个问题
这是关于grand-central-dispatch
内部结构的一个相当广泛的问题。我很难理解dump
ED的输出,因为WWDC为GCD制作的10个视频和幻灯片已不再公开。我也不知道开源的libdispatch
回购(谢谢Rob)。这不一定是个问题,但SO上没有相关的QA详细解释这个话题。
为什么选择GCD
根据WWDC的10 GCD转录本(感谢Rob),API背后的主要思想是简化与使用#selector
API进行多线程相关的样板。
GCD
的好处
苹果发布了一个新的基于block
的API,而不是使用函数指针,还启用了类型安全代码,如果块的类型签名错误,该代码不会崩溃。在函数参数、局部变量和@property
声明中使用typedef
s也使代码更加简洁。队列允许您将代码和某些状态捕获为一块数据,这些数据在后台自动管理、排队和执行。
同一个会话提到了GCD如何在后台管理底层线程。当需要执行块时,它将块排入队列以在线程上执行,然后当不再引用这些线程时释放这些线程(确切地说是PThread
)。GCD自动管理线程,并且不公开这个API-当DispatchWorkItem
退出队列时,GCD为这个块创建一个线程来执行
performSelector
的缺点
performSelector:onThread:withObject:waitUntilDone:
有许多缺点,这些缺点表明,对于并发、等待和同步等现代挑战,设计很差。在CCD_ 23中切换线程时导致末日金字塔。此外,NSObject.performSelector
系列的线程方法是不灵活和有限的:
- 没有用于优化特定线程上的并发、初始非活动或同步的选项。与GCD不同
- 只有选择器可以分派到新线程(糟糕)
- 给定函数的大量线程会导致混乱的代码(末日金字塔)
- 不支持无限制排队(在iOS 4中宣布GCD时)
NSOperation
API。NSOperation
s是一个高级、详细的API,在iOS4中引入调度元素(低级API,后来成为GCD)后变得更加强大 - 许多错误与未处理的无效
Selector
错误有关(类型安全)
DispatchQueue
内部构件
我相信xref
、ref
和sref
是内部寄存器,用于管理自动引用计数的引用计数。GCD在大多数情况下都会在需要时调用dispatch_retain
和dispatch_release
,因此我们不必担心在执行完所有块后释放队列。然而,在某些情况下,开发人员可以手动调用retain
和release
,以确保即使不直接使用队列也能保留。当在具有正引用计数的队列上调用release
时,这些寄存器允许libDispatch
崩溃,以便更好地处理错误。
当调用具有DispatchQueue.global().async
或类似的块时,我相信这会增加该队列的引用计数(xref
和ref
)。
问题中的变量没有明确记录,但我可以告诉你:
xref
统计对一般DispatchQueue
的外部引用的数量- CCD_ 43计数对一般CCD_ 44的引用的总数
sref
统计对API串行/并发/运行循环队列、源和mach通道的引用数量(这些引用需要以不同的方式跟踪,因为它们使用不同的类型表示)
in-barrier
看起来像一个内部状态标志(DispatchWorkItemFlag
),用于跟踪是否应该调度提交到并发队列的新工作项。只有在屏障工作项完成后,队列才会返回到对屏障之后提交的工作项进行调度。in-flight
表示当前没有有效的屏障。
state
也没有明确记录,但我认为它指向内存,在内存中,块可以访问块调度范围中的变量。