1、什么是GCD
GCD是异步执行任务的技术之一。一般将应用程序中记述的线程管理用代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现的,因此可统一管理,也可执行任务,这样就比以前的线程更有效率。
下面举个简单的例子:
dispatch_async(queue, ^{ /* 处理长时间的任务,例如数据库访问等等 */ /* 长时间处理完成以后,主线程使用该处理结果 */ dispatch_async(dispatch_get_main_queue(), ^{ /* 刷新界面等 */ }); });
2、GCD的API
2.1、Dispatch Queue(执行处理的等待队列)
Dispatch Queue按照追加的顺序(先进先出FIFO)执行处理。Dispatch Queue有两种,如下所示:
Serial Dispatch Queue | 等待现在执行中处理结束 |
Concurrent Dispatch Queue | 不等待现在执行中处理结束 |
创建Dispatch Queue方法有如下几种:
第一种:dispatch_queue_create函数生成Dispatch Queue
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
第一个参数指定Dispatch Queue的名称,Dispatch Queue的名称推荐使用应用程序ID这种逆序全程域名。第二个参数用来指定Dispatch Queue的类型,如果为NULL,则为Serial Dispatch Queue,如果为DISPATCH_QUEUE_CONCURRENT,则为Concurrent Dispatch Queue.
另外,需要注意如果你创建的APP的deployment target是mac OS 10.8以及以后或者ios v6.0以及以后,通过dispatch_queue_create创建的dispatch_queue_t对象以及可以被ARC管理,程序员不必手动释放。在这之前的,必须由程序员负责释放,它不在ARC的管理范围之内。因此在使用结束后通过dispatch_release函数释放。
第二种:Main Dispatch Queue/Global Dispatch Queue
这种方法是获取系统提供的标准Dispatch Queue。其中Main Dispatch Queue是在主线程中执行的Dispatch Queue;Global Dispatch Queue是所有应用程序都能使用的Concurrent Dispatch Queue,它分为四个优先级:高优先级、默认优先级、低优先级和后台优先级。
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue(); //最高优先级 dispatch_queue_t highDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); //默认优先级 dispatch_queue_t defaultDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2.2 dispatch_async 和 dispatch_sync
dispatch_async表示非同步地将指定的block追加到指定的Dispatch Queue中,然后立即返回。dispatch_sync表示同步地将指定的block追加到Dispatch Queue中,在追加的block结束之前,dispatch_sync函数会一直等待。下面两个例子都会发生死锁:
dispatch_queue_t queue = dispatch_get_main_queue(); //因为使用dispatch_sync,当前线程即主线程挂起,等待block执行完毕。而block也是在主线程执行,但是主线程已经挂起,所以进入死锁状态 dispatch_sync(queue, ^{ NSLog(@"hello?"); });
dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{ dispatch_sync(queue, ^{ NSLog(@"hello?"); }); });
2.3 Dispatch Group
在追加到Dispatch Queue中的多个处理全部结束后想执行结束处理,在这种情况下使用Dispatch Group。下面看两端代码:
代码1:
dispatch_group_t dispatchGroup = dispatch_group_create(); dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_1"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_2"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_3"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_4"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_5"); }); dispatch_group_notify(dispatchGroup, dispatchQueue, ^{ NSLog(@"end"); });
代码2:
dispatch_group_t dispatchGroup = dispatch_group_create(); dispatch_queue_t dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_1"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_2"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_3"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_4"); }); dispatch_group_async(dispatchGroup, dispatchQueue, ^{ NSLog(@"gg_5"); }); dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER); NSLog(@"end");
代码1与代码2最大的区别就是是否阻塞当前线程。代码1工作机制是:当检测到所有添加到group中处理执行结束后,就把结束处理追加到Dispatch Queue中,因此代码1不会阻塞当前线程。代码2工作机制是:当所有添加到group中处理执行结束之前,当前线程处于阻塞状态,直到group中所有处理执行完成或者超时。
另外,dispatch_group_wait函数的返回值为0,就表示全部处理都执行结束了,如果不为0,则表示超时而返回了。
2.4、dispatch_barrier_sync 和 dispatch_barrier_async
共同点:
1、等待在它前面插入队列的任务先执行完
2、等待他们自己的任务执行完再执行后面的任务
不同点:
1、dispatch_barrier_sync将自己的任务插入到队列的时候,需要等待自己的任务结束之后才会继续插入被写在它后面的任务,然后执行他们。
2、dispatch_barrier_async将自己的任务插入到队列之后,不会等待自己的任务结束,它会继续把后面的任务插入到队列,然后等待自己的任务结束后才执行后面的任务。
2.4、dispatch_suspend/dispatch_resume
dispatch_suspend(queue);//挂起指定的Dispatch Queue
dispatch_resume(queue);//恢复指定的Dispatch Queue
注意:这些函数对已经执行的处理没有影响。挂起后,追加到Dispatch Queue中但尚未执行的处理在此之后停止执行。而恢复则使得这些处理能够继续执行。
2.5、dispatch_apply
dispatch_apply是指按照指定的次数将指定的block追加到指定的Dispatch Queue中,并等待全部处理执行结束。类似dispatch_sync函数和Dispatch group的关联API,例如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, queue, ^(size_t index) { NSLog(@"%zu",index); }); NSLog(@"done");
2.6、dispatch_after
注意:dispatch_after函数并不是在指定时间后执行处理,而只是在指定时间追加处理到Dispatch Queue。虽然在有严格时间的要求下使用时会出现问题,但在想大致延迟执行处理时,该函数是非常有效的。