GCD使用介绍

1、概念数组

一、同步异步:
    a、同步 dispatch_sync():同步执行会等待当前任务执行完再向下执行
    b、异步  dispatch_async():不等待当前任务执行完,而是把任务提交后直接向下执行,不等待提交的任务并发

二、队列
    a、串行队列:提交到串行队列的任务会一个一个按顺序执行,上一个任务完成后、再执行下一个
    建立方式(2种同样):
                一、dispatch_queue_create("tongbu", NULL)
                二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_SERIAL);
                         参数1:队列标签 参数2:队列类型(并发)
                三、dispatch_get_main_queue() 主队列也是串行队列
    b、并发队列:提交到并发队列的任务对并发执行,每一个任务从提交的那一时刻起都会为它建立一个线
程,且没法肯定哪个任务先完成。
     建立方式(2种同样):
                一、dispatch_get_global_queue(0, 0)//获取系统的全局并发队列
                        其中,参数1 有如下可选
                         DISPATCH_QUEUE_PRIORITY_HIGH        //2
                        DISPATCH_QUEUE_PRIORITY_DEFAULT  //0 通常选这个便可
                        DISPATCH_QUEUE_PRIORITY_LOW        //-2
                        DISPATCH_QUEUE_PRIORITY_BACKGROUND // INT16_MIN  ( -32768)     
                二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT)//本身建立
                        参数1:队列标签 参数2:队列类型(并发)
特别提醒:dispatch_queue_create 每执行一次就会建立一个新对象,
                dispatch_queue_t queue1 =  dispatch_queue_create("tongbu", NULL);
                dispatch_queue_t queue2=  dispatch_queue_create("tongbu", NULL);
                此时queue1 != queue2

                因此使用时若是想要使用同一队列,必定要将其存储起来
!并发队列 执行时,并不必定会将添加到队列的任务所有一块儿执行,而是处理数量取决于系统的状态(CPU核数,负载。。)先执行前几个,好比一次性添加了10000个任务到并发队列,他可能因为负载缘由只并发执行了第40个,当根据执行状况再并发后续任务app

2、使用
    同步异步与队列结合使用异步

    连续添加十个任务
    组合1:同步 + 串行    

                无心义,连续添加十个任务,会加一个执行一个,第一个执行完,执行加入第二个
    组合2:异步 + 串行

                十个任务是按顺序添加,可是因为是异步添加,不会影响 "结束"的执行,同时,队列时串行队列,因此会挨个执行
    组合3:同步 + 并发

            无心义,觉得他会等待添加的任务完成在继续下一步
    组合4:异步 + 并发

每一个任务都会开启新线程去并发执行,至关因而个任务同时并发执行,且不会阻塞当前程序async

3、函数方法
   一、 dispatch_barrier_async函数

dispatch_queue_t queue = dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, readFile);
    dispatch_async(queue, readFile);
    //会等上面提交的任务完成后再去写,写完后才继续执行下面的提交任务,防止了读写竞争
    dispatch_barrier_async(queue, writeFile);
    
    dispatch_async(queue, readFile);
    dispatch_async(queue, readFile);

这样,多个read不会互相影响,提升了读性能,且不影响写操做(注意上面的是并发队列)性能

二、挂起/恢复
    注意:它的原理相似于引用计数,一个queue若是调用N次dispatch_suspend,那么要想恢复,就须要调用N次dispatch_resume才能够继续,并且dispatch_resume函数不能随意调用,只有当前队列被挂起后才能够对它使用该函数,不然会报错spa

dispatch_queue_t queue =  dispatch_queue_create("tongbu", NULL);
    dispatch_suspend(queue);//挂起队列
    dispatch_resume(queue);//恢复队列

三、定时器线程

//dispatchQueue:该定时器任务在哪一个队列执行
    //intervalInSeconds: 间隔时间
    //leewayInSeconds :设置为0便可 
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
         //do something ...
    });
    //一次暂停对应一次开始,默认建立完成timer时是暂停的,原理见上一节
    //开始(不暂停时不能随意调用)
    dispatch_resume(timer);
    //暂停
    dispatch_suspend(timer);
    //销毁
    dispatch_source_cancel(_timer);

须要注意:要持有 timer 和 queue,不能让其销毁,不然定时器失效。

四、dispatch_semaphore_t 信号量
异步的向数组中添加对象会产生内存问题,须要进行锁处理,可使用dispatch_semaphore_t信号量机制实现code

- (void)test1 {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//并发队列
    NSMutableArray *array = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < 10000; ++i) {
        dispatch_async(queue, ^{
            [array addObject:[NSNumber numberWithInteger:i]];//这里会产生内存问题
        });
    }
    NSLog(@"完成");
}

使用dispatch_semaphore_t

- (void)test2 {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSMutableArray *array = [[NSMutableArray alloc] init];
    //信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    for (int i = 0; i < 10000; ++i) {
        dispatch_async(queue, ^{
            
            //一、该函数会阻塞,等待直到semaphore计数 >= 1, 而后 内部将计数减1,而后该函数执行完返回
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            //二、执行到此处时, semaphore计数为0,表明没有线程修改array
            [array addObject:[NSNumber numberWithInteger:i]];
            
            //三、处理结束,修改信号量semaphore 加1,若是有dispatch_semaphore_wait函数等待,那么最早等待的那个线程就先执行
            dispatch_semaphore_signal(semaphore);
            
        });
    }
    NSLog(@"完成");
}

dispatch_semaphore_t,是一个持有计数的信号

//建立信号 设置信号量总数
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
    
    //释放一个信号,semaphore信号计数 +1
    dispatch_semaphore_signal(semaphore);
    
    //等待信号,当信号计数 >= 1 时就能够继续向下执行,同时 它将计数 进行减1 操做,,不然一直等待
    //参数2 为超时时间,
    //函数返回result: 0 表明success 信号计数 >=1, 非0 表明超时了,信号计数 <1
    long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

适用于有限资源的访问限制
五、Group

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    
    //添加任务到组
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务2");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务3");
        [NSThread sleepForTimeInterval:5];
    });
    //任务1,2,3都执行完后才执行该任务
    dispatch_group_notify(group, queue, ^{
        NSLog(@"最后打印");
    });
    
    dispatch_time_t time =  dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
    //wait函数会阻塞当前线程,直到超时或者group提早执行完成,也能够将等待时间设置为DISPATCH_TIME_NOW,当即返回结果,不会阻塞
    // result: 0 表明已完成, 非0 未完成,已超时
    long result = dispatch_group_wait(group, time);
    NSLog(@"%ld", result);

六、dispatch_apply

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //按指定次数将block追加到queue
    //会阻塞当前线程,等待任务完成
    dispatch_apply(10, queue, ^(size_t i) {
        NSLog(@"%zu", i);
    });
    
    NSLog(@"最后打印");
相关文章
相关标签/搜索