GCD队列管理之YYDispatchQueuePool
前言
iOS
中,我们经常使用GCD
来进行并发操作,我们并不需要关心线程的管理,Dispatch Queue
会自动帮我们处理线程的创建和释放,在极大的简化并发操作的同时,某些情况下,Dispatch Queue
的滥用可能会导致应用挂起,如向并发队列中添加阻塞的Block
,阻塞的Block
会导致系统创建更多的线程来处理任务,而GCD
线程池的最大线程数为64个,所以一旦达到最大值,应用将挂起。
接下来,我将列出一些解决方案,来更好的使用Dispatch Queue
。
YYDispatchQueue
YYDispatchQueue的主要思想是使用串行队列来替换并发队列,可以为指定的NSQualityOfService
创建一个队列池,由YYDispatchQueuePool
对象来进行管理,每一种NSQualityOfService
最多可以创建32个串行队列,通过- (dispatch_queue_t)queue;
方法来获取可用队列,其采用Round Robin
轮询算法。
除了可以创建队列池来管理并发外,还可以通过C
的全局函数(dispatch_queue_t YYDispatchQueueGetForQOS(NSQualityOfService qos)
)来获取特定的NSQualityOfService
串行队列,队列由全局的队列池来管理,每一种NSQualityOfService
的串行队列数与核数相同,这样可以尽可能的减少线程之间的上下文切换。
YYDispatchQueuePool
对象使用YYDispatchContext
struct
来管理队列池,代码目前还存在内存泄露的问题,因为struct
是在堆上分配的内存,最后使用YYDispatchContextRelease
释放context
时只释放了结构体成员的内存空间,而没有释放结构体自己申请的空间,解决方法如下注释,加上free(context)
即可。
1 | typedef struct { |
NSOperationQueue
使用NSOperationQueue
,设置maxConcurrentOperationCount
来控制并发量。
Dispatch Semaphores
使用Dispatch Queue
时,可以用信号量来控制并发的数量,GCD
提供信号量的支持,dispatch_semaphore_t
用来表示信号量。在往队列添加任务之前,可以使用dispatch_semaphore_wait
来获取信号量,成功获取后即可往队列中添加任务,当任务完成时,使用dispatch_semaphore_signal
来释放信号量。
1 | // 示例代码需要封装一下,不要直接在主线程或次级线程中直接调用dispatch_semaphore_wait,可能会引发UI挂起 |
附录
- https://stackoverflow.com/questions/7213845/number-of-threads-created-by-gcd
- https://github.com/ibireme/YYDispatchQueuePool
- https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW24