一、关于GCD
GCD为Grand Central Dispatch的缩写,是苹果开发的一种操作机制,在Mac OS X 10.6中首次推出,并引入到了iOS4.0。
GCD是一套低层API,不是Cocoa框架的一部分,从基本功能上讲,GCD有点像NSOperationQueue,他们都可以将单一任务提交至工作队列来并发地或者串行地执行。GCD比之NSOpertionQueue更底层更高效,开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。
GCD的主要部件是一个FIFO队列和一个线程池,前者用来添加任务,后者用来执行任务。GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行(但不保证一定先执行结束)。
GCD的API很大程度上基于block,当然,GCD也可以脱离block来使用,比如使用传统c机制提供函数指针和上下文指针,实践证明,当配合block使用时,GCD非常简单易用且能发挥其最大能力。
二、GCD的使用
dispatch queue主要有以下几种:
1)运行在主线程的 Main queue
dispatch_async(dispatch_get_main_queue(), ^{
// something
});
2)并行队列 global queue
一般用于后台执行,并行队列的执行顺序与其加入队列的顺序相同(FIFO)。
dispatch_async(dispatch_get_global_queue(0, 0),^{
//something
});
通常,我们可以在global_queue中做一些long-running的任务,完成后在main_queue中更新UI,以避免UI阻塞:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// long-running task
dispatch_async(dispatch_get_main_queue(), ^{
// update UI
});
});
上面提到dispatch_async这个接口,用来提交blcok给指定queue进行异步执行。这个接口会在成功提交block后立即返回,然后继续执行下去。
与之相对应的是dispatch_sync接口,提交block以供同步执行,这个接口会等到block执行结束才返回。
3)串行队列 serial queues
一般用于按顺序同步访问,串行队列在同一个时间只执行一个任务。
dispatch_queue_t urls_queue =dispatch_queue_create("blog.tang.com", NULL);
dispatch_async(urls_queue, ^{
// your code
});
dispatch_release(urls_queue);
4)只被执行一次的 dispatch_once
它可以保证整个应用程序生命周期中某段代码只被执行一次!
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});
5)延迟执行 dispatch_after
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(),^(void){
// code to be executed on the main queue after delay
});
6)合并汇总结果 dispatch_group
可能经常会有这样一种情况:我们现在有2个Block要执行,我们不在乎它们执行的顺序,我们只希望在这2个Block执行完之后再执行某个操作。这个时候就需要使用dispatch_group了:
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
// 并行执行的线程一
});
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
// 并行执行的线程二
});
dispatch_group_notify(group,dispatch_get_global_queue(0,0), ^{
// 汇总结果或者说同步地等待一段时间看是否结束:
});
7)设置优先级 dispatch_set_target_queue
通过dispatch_set_target_queue函数可以设置一个dispatch queue的优先级,或者指定一个dispatch source相应的事件处理提交到哪个queue上。
dispatch_set_target_queue(serialQ, globalQ);
8)重复执行 dispatch_apply
dispatch_apply(10, globalQ, ^(size_t index) {
// do sth. 10 times
});
9)同步地等待一段时间看是否结束 dispatch_group_wait
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
dispatch_group_wait(group, time);
需要注意的是,dispatch_group_wait实际上会使当前的线程处于等待的状态,也就是说如果是在主线程执行dispatch_group_wait,在上面的Block执行完之前,主线程会处于卡死的状态。
10)栅栏 dispatch_barrier_async
通过dispatch_barrier_async函数提交的任务会等它前面的任务执行结束才开始,然后它后面的任务必须等它执行完毕才能开始。
dispatch_async(concurrentQ, blk0);
dispatch_async(concurrentQ, blk1);
dispatch_barrier_async(concurrentQ, blk_barrier);
dispatch_async(concurrentQ, blk2);
dispatch_barrier_async就如同它的名字一样,在队列执行的任务中增加“栅栏”,在增加“栅栏”之前已经开始执行的block将会继续执行,当dispatch_barrier_async开始执行的时候其他的block处于等待状态,dispatch_barrier_async的任务执行完后,其后的block才会执行。
11)线程队列的挂起与执行
// 挂起队列
dispatch_suspend(queue);
// 恢复队列执行
dispatch_resume(queue);
这里需要特别说明一下:GCD原生并不支持取消操作。dispatch_suspend函数也只能暂停开启新的未执行的block,已经处于执行中的block是无法暂停的。
参考博文:
1、http://justsee.iteye.com/blog/1883409
2、http://www.cnblogs.com/pure/archive/2013/03/31/2977420.html
3、http://blog.csdn.net/jasonblog/article/details/7816999