iOS GCD中控制最大并发数

一、概述

在GCD中有两种队列,分别是串行队列和并发队列。在串行队列中,同一时间只有一个任务在执行,不能充分利用多核 CPU 的资源,效率较低。

并发队列可以分配多个线程,同时处理不同的任务;效率虽然提升了,但是多线程的并发是用时间片轮转方法实现的,线程创建、销毁、上下文切换等会消耗CPU 资源。

目前iPhone的处理器是多核(2个、4个),适当的并发可以提高效率,但是无节制地并发,如将大量任务不加思索就用并发队列来执行,这只会大量增加线程数,抢占CPU资源,甚至会挤占掉主线程的 CPU 资源(极端情况)。

此外,提交给并发队列的任务中,有些任务内部会有全局的锁(如 CoreText 绘制时的 CGFont 内部锁),会导致线程休眠、阻塞;一旦这类任务多,并发队列还需要创建新的线程来执行其他任务;这种情况下,线程数大量增加是避免不了的。

二、优雅的NSOperationQueue  
NSOperationQueue是iOS提供的工作队列,开发者只需要将任务封装在NSOperation的子类(NSBlockOperation、NSInvocationOperation或自定义NSOperation子类)中,然后添加进NSOperationQueue队列,队列就会按照优先顺序及工作的从属依赖关系(如果有的话)组织执行。

NSOperationQueue中,已经考虑到了最大并发数的问题,并提供了maxConcurrentOperationCount属性设置最大并发数(该属性需要在任务添加到队列中之前进行设置)。maxConcurrentOperationCount默认值是-1;如果值设为0,那么不会执行任何任务;如果值设为1,那么该队列是串行的;如果大于1,那么是并行的。

NSOperationQueue *queue = [[NSOperationQueue alloc]init];

queue.maxConcurrentOperationCount = 2;//添加Operation任务...

第三方库如SDWebImage库和AFNetworking 中就是采用NSOperationQueue来控制最大并发数的。

三、在GCD中如何控制并发 

GCD多线程方案很优秀,NSOperationQueue的底层就是用GCD来实现的。

NSOperationQueue在控制最大并发数上的确很方便,但是GCD也提供了某些机制可以实现控制最大并发数的效果。

开发中NSOperationQueue和GCD都可以用,视场景而定。

1、GCD的信号量机制(dispatch_semaphore)

信号量是一个整型值,有初始计数值;可以接收通知信号和等待信号。当信号量收到通知信号时,计数+1;当信号量收到等待信号时,计数-1;如果信号量为0,线程会被阻塞,直到信号量大于0,才会继续下去。

使用信号量机制可以实现线程的同步,也可以控制最大并发数。此处就控制了最大并发量为5 , 但是比起NSOperationQueue还是差点.

    dispatch_semaphore_t sem = dispatch_semaphore_create(5);
    
    for (int i = 0; i<100; i++) {
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
            
            NSLog(@"%@",[NSThread currentThread]);
            sleep(1);
            
            dispatch_semaphore_signal(sem);
            
        });
        
    }

在iOS开发中,YYKit组件中的YYDispatchQueuePool也能控制并发队列的并发数;其思路是为不同优先级创建和 CPU 数量相同的 serial queue,每次从 pool 中获取 queue 时,会轮询返回其中一个 queue。

QSDispatchQueue是使用信号量让并发队列中的任务并发数得到抑制;YYDispatchQueuePool是让一定数量的串行队列代替并发队列,避开了并发队列不好控制并发数的问题。


 

发布了101 篇原创文章 · 获赞 33 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/u014600626/article/details/104701921