变更记录
方案名称 专题 - GCD 介绍与使用(二)
关键字 专题 \ Block \ Dispatch \ GCD \ 异步 \ 并行
需求场景
熟悉 Objective-C GCD
参考链接
GitHub - nixzhu/dev-blog - GCD 深入理解:第一部分
GitHub - nixzhu/dev-blog - GCD 深入理解:第二部分
Ray Wenderlich - Grand Central Dispatch In-Depth: Part 1/2
Ray Wenderlich - Grand Central Dispatch In-Depth: Part 2/2
伯乐在线 - GCD那些事 (推荐)
详细内容 以下内容整理自 伯乐在线 - GCD那些事 原文出处 : 像晨宇(@向晨宇_)
第一组 API : 信号量相关
dispatch_semaphore_t
dispatch_semaphore_wait
dispatch_semaphore_signal
作用 : 在多线程下控制多线程的并发数目
创建信号量,可以设置信号量的资源数。0 表示没有资源,调用 dispatch_semaphore_wait 会立即等待dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
等待信号,可以设置超时参数。该函数返回 0 表示得到通知,非 0 表示超时dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
通知信号,如果等待线程被唤醒则返回非 0 ,否则返回 0dispatch_semaphore_signal(semaphore);
使用场景一 :并发队列 每执行完 10 个任务后,休息两秒,再继续执行 10 个任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -(void) testSemaphore{ dispatch_group_t group = dispatch_group_create(); dispatch_semaphore_t semaphore = dispatch_semaphore_create(10); //信号总量是 10 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); for (int i = 0; i 100; i++) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//信号量 -1 dispatch_group_async(group, queue, ^{ NSLog(@"%i",i); sleep(2); dispatch_semaphore_signal(semaphore); //信号量 +1 }); } dispatch_group_wait(group, DISPATCH_TIME_FOREVER); }
执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2016-06-01 20:30:35.113 XXGCD[39559:306278] 7 2016-06-01 20:30:35.113 XXGCD[39559:306277] 6 2016-06-01 20:30:35.113 XXGCD[39559:306271] 0 2016-06-01 20:30:35.113 XXGCD[39559:306274] 3 2016-06-01 20:30:35.113 XXGCD[39559:306270] 1 2016-06-01 20:30:35.113 XXGCD[39559:306272] 2 2016-06-01 20:30:35.113 XXGCD[39559:306275] 4 2016-06-01 20:30:35.113 XXGCD[39559:306276] 5 2016-06-01 20:30:35.113 XXGCD[39559:306279] 8 2016-06-01 20:30:35.113 XXGCD[39559:306280] 9 2016-06-01 20:30:37.117 XXGCD[39559:306272] 11 2016-06-01 20:30:37.117 XXGCD[39559:306270] 12 2016-06-01 20:30:37.117 XXGCD[39559:306275] 10 2016-06-01 20:30:37.117 XXGCD[39559:306280] 13 2016-06-01 20:30:37.117 XXGCD[39559:306276] 15 2016-06-01 20:30:37.117 XXGCD[39559:306279] 14 2016-06-01 20:30:37.117 XXGCD[39559:306274] 16 2016-06-01 20:30:37.117 XXGCD[39559:306277] 17 2016-06-01 20:30:37.117 XXGCD[39559:306278] 18 2016-06-01 20:30:37.117 XXGCD[39559:306271] 19
使用场景二 :等待异步线程完成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -(void) testAsynFinished{ __block BOOL isok = NO; dispatch_semaphore_t sema = dispatch_semaphore_create(0); XXEngine *engine = [[XXEngine alloc] init]; [engine queryCompletion:^(BOOL isOpen) { // sleep 了 3 秒 isok = isOpen; dispatch_semaphore_signal(sema); NSLog(@"success!"); } onError:^(BOOL isOpen, int errorCode) { isok = NO; dispatch_semaphore_signal(sema); NSLog(@"error!"); }]; NSLog(@"finished"); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); }
执行结果
1 2 2016-06-02 15:01:06.168 XXGCD[35443:290673] success! 2016-06-02 15:01:06.168 XXGCD[35443:290673] finished
使用场景三 :生产者,消费者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 -(void) testProductAndConsumer{ dispatch_semaphore_t sem = dispatch_semaphore_create(0); dispatch_queue_t producerQueue = dispatch_queue_create("producer", DISPATCH_QUEUE_CONCURRENT);//生产者线程跑的队列 dispatch_queue_t consumerQueue = dispatch_queue_create("consumer", DISPATCH_QUEUE_CONCURRENT);//消费者线程跑的队列 __block int cakeNumber = 0; dispatch_async(producerQueue, ^{ //生产者队列 while (1) { if (!dispatch_semaphore_signal(sem)) { NSLog(@"Product:生产出了第%d个蛋糕",++cakeNumber); sleep(1); //wait for a while continue; } } }); dispatch_async(consumerQueue, ^{//消费者队列 while (1) { if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 0*NSEC_PER_SEC))){ if(cakeNumber > 0){ NSLog(@"Consumer:拿到了第%d个蛋糕",cakeNumber--); } continue; } } }); }
执行结果
1 2 3 4 2016-06-02 15:04:18.785 XXGCD[35593:294211] Product:生产出了第1个蛋糕 2016-06-02 15:04:18.785 XXGCD[35593:294209] Consumer:拿到了第1个蛋糕 2016-06-02 15:04:19.790 XXGCD[35593:294209] Consumer:拿到了第1个蛋糕 2016-06-02 15:04:19.790 XXGCD[35593:294211] Product:生产出了第1个蛋糕
第二组 API : Group 相关
dispatch_group_t
dispatch_group_notify
作用 : 用来阻塞一个线程,直到一个或多个任务完成执行
使用场景一 :并发队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -(void) testGCDGroup{ dispatch_group_t group = dispatch_group_create(); for(int i = 0; i 10; i++) { dispatch_group_enter(group); [[XXEngine instance] doAsyncWorkWithCompletionBlock:^{ dispatch_group_leave(group); }]; } dispatch_group_wait(group, DISPATCH_TIME_FOREVER); NSLog(@"testGCDGroup1 更新UI操作"); }
等价于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -(void) testGCDGroup2{ dispatch_group_t group = dispatch_group_create(); for(int i = 0; i 10; i++) { dispatch_group_enter(group); [[XXEngine instance] doAsyncWorkWithCompletionBlock:^{ dispatch_group_leave(group); }]; } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"testGCDGroup2 更新UI操作"); }); }
执行结果
1 2 3 4 5 6 7 8 9 10 11 2016-06-02 15:29:54.392 XXGCD[36197:313551] test 2016-06-02 15:29:54.392 XXGCD[36197:313569] test 2016-06-02 15:29:54.393 XXGCD[36197:313572] test 2016-06-02 15:29:54.393 XXGCD[36197:313571] test 2016-06-02 15:29:54.392 XXGCD[36197:313558] test 2016-06-02 15:29:54.392 XXGCD[36197:313568] test 2016-06-02 15:29:54.392 XXGCD[36197:313563] test 2016-06-02 15:29:54.393 XXGCD[36197:313570] test 2016-06-02 15:29:54.393 XXGCD[36197:313573] test 2016-06-02 15:29:54.393 XXGCD[36197:313574] test 2016-06-02 15:29:56.398 XXGCD[36197:313513] testGCDGroup1 更新UI操作
使用场景二 :等待异步线程完成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 -(void) testGCDGroup3{ 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, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group1"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"group2"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group3"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"testGCDGroup3 更新UI操作"); }); }
执行结果
1 2 3 4 2016-06-02 15:58:29.041 XXGCD[36675:337871] group1 2016-06-02 15:58:30.041 XXGCD[36675:337880] group2 2016-06-02 15:58:31.043 XXGCD[36675:337884] group3 2016-06-02 15:58:31.043 XXGCD[36675:337834] testGCDGroup3 更新UI操作
第三组 API : 同步函数
会阻塞当前线程直到所有循环迭代执行完成。当提交到并发 queue 时,循环迭代的执行顺序是不确定的
使用场景一 :并发队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static int i = 0; -(void) testGCDApply{ dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, globalQ, ^(size_t index) { // 执行10次 [self printTest]; }); } -(void) printTest{ NSLog(@"%d",++i); }
执行结果
1 2 3 4 5 6 7 8 9 10 2016-06-02 16:06:50.799 XXGCD[37133:347348] 6 2016-06-02 16:06:50.799 XXGCD[37133:347329] 2 2016-06-02 16:06:50.799 XXGCD[37133:347346] 8 2016-06-02 16:06:50.799 XXGCD[37133:347336] 1 2016-06-02 16:06:50.799 XXGCD[37133:347340] 3 2016-06-02 16:06:50.799 XXGCD[37133:347296] 4 2016-06-02 16:06:50.799 XXGCD[37133:347347] 7 2016-06-02 16:06:50.799 XXGCD[37133:347349] 5 2016-06-02 16:06:50.799 XXGCD[37133:347329] 9 2016-06-02 16:06:50.799 XXGCD[37133:347348] 10
第四组 API : 时间相关
dispatch_source_set_timer
dispatch_suspend
dispatch_resume
dispatch_source_cancel
dispatch_suspend
:暂停dispatch_source_t
dispatch_resume
:恢复dispatch_source_t
dispatch_cancel
:取消dispatch_source_t
使用场景一 : 实现 NSTimer 相关功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @interface XXGCDTimer() { dispatch_source_t _timer; } @end @implementation XXGCDTimer -(void) startGCDTimer{ NSTimeInterval period = 1.0; //设置时间间隔 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行 dispatch_source_set_event_handler(_timer, ^{ //在这里执行事件 NSLog(@"每秒执行test"); }); dispatch_resume(_timer); } -(void) pauseTimer{ if(_timer){ dispatch_suspend(_timer); } } -(void) resumeTimer{ if(_timer){ dispatch_resume(_timer); } } -(void) stopTimer{ if(_timer){ dispatch_source_cancel(_timer); _timer = nil; } } @end
更多 API 及使用场景见参考链接
dispatch_barrier_async
dispatch_sync 和 dispatch_async
dispatch_get_global_queue
dispatch_once
dispatch_after
效果图 (无)
备注