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