GCD是Grand Central Dispatch 的缩写. 即多线程优化技术.
它可以提供线程安全的队列,串行队列和并行队列,同步和异步执行任务.在队列中, 有很多回调块的执行单位, 完成一个任务后就回调块继续执行.GCD负责线程的创建,管理及释放,我们不用管理者一块.
GCD队列特点:
1. 不是为了通常的数据存储而设计的
2. 它没有取消功能, 没有随机访问功能
3. 使用合理的数据结构来解决问题
4. 自动的线程创建和回收
5. 通过块来实现回调, 极大简化代码复杂度
GCD队列类型
dispatch_get_main_queue()
可以取到,它是一个串行队列, 运行在主线程, 主要用做对视图的更新操作.dispatch_get_global_queue(long identifier, unsigned long flags)
可以创建. 它是一个并行队列, dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
创建,可以使串行或者并行, 通过 attr 参数设置串行队列特点: 先进先出, 原子性入队(线程安全), 自动出队.每次只执行一个任务,按入队顺序执行.
并行队列特点: 它保证开始执行的顺序是入队的顺序, 但是任务之间是同时进行的, 不能保证先入队的一定先执行完成
异步方法 ,功能类似于 performSelector: onThread: withObject: waitUntilDone:
,我们何时使用呢?
同步方法 ,功能类似于 performSelector: onThread: withObject: waitUntilDone:
, 我们何时使用呢?
简单的创建队列
dispatch_queue_t queue =dispatch_queue_create("myQueue",DISPATCH_QUEUE_SERIAL);
// DISPATCH_QUEUE_CONCURRENT 并行
// DISPATCH_QUEUE_SIRAIL 串行
dispatch_async(queue, ^{
// your implemente
});
当我们遇到线程安全读写问题的时候,比如访问或这只某些线程不安全的属性,例如 NSMutableArray, 需要使用 dispatch barrier 保证读写唯一性,它相当于一个读写锁, 会在并行队列中保证执行的唯一性,简单的理解就是一旦进入了barrier中, 不论什么队列, 执行barrier的时候, 这个队列暂时变成了串行队列.
// 这里因为可变数组是线程不安全的, 所以我们使用dispatch barrier来保证即使在多线性中访问也是安全的
- (void)addPhoto:(Photo *)photo
{
// Photo 是我们自定义的model
// concurrentQueue 是并行队列
// _photosArray 是一个可变数组
if (photo) {
dispatch_barrier_async(self.concurrentQueue,^{
[_photosArray addObject:photo];
dispatch_async(dispatch_get_main_queue(),^{
// 继续更新UI之类的
});
});
}
}
可以保证线程安全的只执行一次,非常有用,适合创建全局使用且创建昂贵的资源
+ (instancetype)sharedManager
{
static Manager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[Manager alloc] init];
// do other things
});
return sharedPhotoManager;
}
延时执行一个任务, 相当于延迟的dispatch_async, 通常使用在main queue上,类似于performSelector: withObject: afterDelay:
的功能
int64_t delay = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// do your implement
});
在使用MRC的时候还需要对GCD队列的参数做Retain Release 操作, 在ARC就不需要了, 编译器已经自动添加了.
void performAsyncWithCallback(id object, dispatch_queue_t q) {
dispatch_retain(q); // 在MRC的时候需要添加
dispatch_async(dispatch_queue_create("q", DISPATCH_QUEUE_CONCURRENT), ^{
dispatch_async(q, ^{
[object callBack];
});
dispatch_release(q); // 在MRC的时候需要添加
});
}
当我们向监听多个异步任务全部完成的时候,就需要为每个任务添加BOOL点判断位, 这个做非常冗余,不友好, 这时我们需要使用dispatch group 来解决, 它可以同步或异步的在完成组内的所有任务的时候发出通知. API 有两种通知方式:
// 异步执行任务
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// 创建group
dispatch_group_t downloadGroup =
dispatch_group_create();
for (NSInteger i = 0; i < 3; i++) {
// 任务开始进入group
dispatch_group_enter(downloadGroup);
// 异步执行任务, 任务使group内部计数加1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// 执行出group, 使group 内部计数减1,达到平衡
dispatch_group_leave(downloadGroup);
});
}
// group_wait 是同步方法, 会阻塞当前前程,只有等待group中所有任务完成后 才能往下执行
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
// some UI operation
});
// group_notify 异步方法, 异步收到group所有任务完成的通知,不会阻塞当前线程.
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// some UI operation
});
});
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), ^{
// 会等待两个线程全结束后, 汇总结果
});
当我们通过 for 循环添加一些任务到队列中的时候,如何才能提高添加速度呢, 我们可以使用dispatch_apply, 它可以异步执行循环内部的实现, 但是它本身是同步的方法, 需要等到循环完全结束后才返回.合适使用它才合适?
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t i) {
// 循环执行 10 次
});
它可以简单轻松的监听系统事件,用户自定义事件等,它可以在任何的队列上传递并处理回调事件, 也可以执行挂起, 恢复操作, 默认创建后是挂起的.创建dispatch_source 会有很多种要监听的类型,比如:
创建source
函数原型, 其中 queue为source执行的,type为source类型, queue可以是我们制定的queue, 也可以是DISPATCH_TARGET_QUEUE_DEFAULT, source默认的queue, 这个队列默认是 default priority global queue,默认级别的全局队列.
dispatch_source_create(dispatch_source_type_t type,
uintptr_t handle,
unsigned long mask,
dispatch_queue_t queue);
调用示例
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
未完待续:
dispatch_set_target_queue
dispatch_queue_set_specific
dispatch_data_t
具体例子可以参考我的例子
GCD例子
参考 Concurrency Programming Guide
参考1
参考2
原文地址:http://blog.csdn.net/mysevenmi/article/details/45330853