GCD的一些用法
2015-05-03 23:43
239 查看
GCD是Grand Central Dispatch 的缩写. 即多线程优化技术.
它可以提供线程安全的队列,串行队列和并行队列,同步和异步执行任务.在队列中, 有很多回调块的执行单位, 完成一个任务后就回调块继续执行.GCD负责线程的创建,管理及释放,我们不用管理者一块.
GCD队列特点:
1. 不是为了通常的数据存储而设计的
2. 它没有取消功能, 没有随机访问功能
3. 使用合理的数据结构来解决问题
4. 自动的线程创建和回收
5. 通过块来实现回调, 极大简化代码复杂度
GCD队列类型
main queue 主队列
global queue 全局队列
自定义队列. 使用
串行队列特点: 先进先出, 原子性入队(线程安全), 自动出队.每次只执行一个任务,按入队顺序执行.
并行队列特点: 它保证开始执行的顺序是入队的顺序, 但是任务之间是同时进行的, 不能保证先入队的一定先执行完成
自定义串行队列: 当我们想要串行的在后台执行一些操作,避免有资源争夺的操作同时执行, 可以使用异步方法,但是如果在操作中需要用到一些方法返回的数据, 最好在异步方法中, 同步调用返回数据.
主队列:通常是等待一些操作完成后更新UI
异步队列: 通常是一些非UI操作处理.
子定义串行队列,小心使用,千万不要再同一个串行队列中使用同步方法, 会造成循环死锁.
主队列. 小心使用, 可能会有死锁.
并行队列. 可以很好的通过dispatch barriers 或者 需要等待结果继续执行的任务.
简单的创建队列
自定义串行队列. 在这里使用 barrier 其实没有什么作用, 串行队列原本就是同一时间只能执行一个任务,
全局并行队列. 在这里不是一个好的选择, 因为会有其他的不是自己的任务被阻塞执行.
自定义并行队列. 在这里执行比较合适, 可以完全自定义.
在使用MRC的时候还需要对GCD队列的参数做Retain Release 操作, 在ARC就不需要了, 编译器已经自动添加了.
dispatch_group_wait 会阻塞当前的线程,等待租内的所有任务都完成或者超时的时候发出通知, 这是同步的.
dispatch_group_notify 会给出一个异步的回调块,它不会阻塞所在的线程
group也可以监听多个线程的任务,在全部结束是发出通知
自定义串行队列. 不要再这里使用, 串行队列会使它无效
主队列. 还是一样, 串行队列使它无效
并行队列. 可以很好的使用它, 尤其是我们向监控任务的进度.
timer计时器的周期性通知事件
UNIX系统的信号通知
文件或端口的事件:读数据, 写数据, 文件被删除,移动,修改,重命名等.
进程的状态事件: 进程退出, 一个信号到达进程, 进程执行或分支
Mach
用户自定义的事件
创建source
函数原型, 其中 queue为source执行的,type为source类型, queue可以是我们制定的queue, 也可以是DISPATCH_TARGET_QUEUE_DEFAULT, source默认的queue, 这个队列默认是 default priority global queue,默认级别的全局队列.
调用示例
未完待续:
dispatch_set_target_queue
dispatch_queue_set_specific
dispatch_data_t
具体例子可以参考我的例子
GCD例子
参考 Concurrency Programming Guide
参考1
参考2
它可以提供线程安全的队列,串行队列和并行队列,同步和异步执行任务.在队列中, 有很多回调块的执行单位, 完成一个任务后就回调块继续执行.GCD负责线程的创建,管理及释放,我们不用管理者一块.
GCD队列特点:
1. 不是为了通常的数据存储而设计的
2. 它没有取消功能, 没有随机访问功能
3. 使用合理的数据结构来解决问题
4. 自动的线程创建和回收
5. 通过块来实现回调, 极大简化代码复杂度
GCD队列类型
main queue 主队列
dispatch_get_main_queue()可以取到,它是一个串行队列, 运行在主线程, 主要用做对视图的更新操作.
global queue 全局队列
dispatch_get_global_queue(long identifier, unsigned long flags)可以创建. 它是一个并行队列,
自定义队列. 使用
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)创建,可以使串行或者并行, 通过 attr 参数设置
串行队列特点: 先进先出, 原子性入队(线程安全), 自动出队.每次只执行一个任务,按入队顺序执行.
并行队列特点: 它保证开始执行的顺序是入队的顺序, 但是任务之间是同时进行的, 不能保证先入队的一定先执行完成
dispatch_async()
异步方法 ,功能类似于performSelector: onThread: withObject: waitUntilDone:,我们何时使用呢?
自定义串行队列: 当我们想要串行的在后台执行一些操作,避免有资源争夺的操作同时执行, 可以使用异步方法,但是如果在操作中需要用到一些方法返回的数据, 最好在异步方法中, 同步调用返回数据.
主队列:通常是等待一些操作完成后更新UI
异步队列: 通常是一些非UI操作处理.
dispatch_sync()
同步方法 ,功能类似于performSelector: onThread: withObject: waitUntilDone:, 我们何时使用呢?
子定义串行队列,小心使用,千万不要再同一个串行队列中使用同步方法, 会造成循环死锁.
主队列. 小心使用, 可能会有死锁.
并行队列. 可以很好的通过dispatch barriers 或者 需要等待结果继续执行的任务.
简单的创建队列
dispatch_queue_t queue =dispatch_queue_create("myQueue",DISPATCH_QUEUE_SERIAL); // DISPATCH_QUEUE_CONCURRENT 并行 // DISPATCH_QUEUE_SIRAIL 串行 dispatch_async(queue, ^{ // your implemente });
dispatch barrier
当我们遇到线程安全读写问题的时候,比如访问或这只某些线程不安全的属性,例如 NSMutableArray, 需要使用 dispatch barrier 保证读写唯一性,它相当于一个读写锁, 会在并行队列中保证执行的唯一性,简单的理解就是一旦进入了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之类的 }); }); } }
dispatch_once
可以保证线程安全的只执行一次,非常有用,适合创建全局使用且创建昂贵的资源+ (instancetype)sharedManager { static Manager *sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedManager = [[Manager alloc] init]; // do other things }); return sharedPhotoManager; }
dispatch_after
延时执行一个任务, 相当于延迟的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的时候需要添加 }); }
Dispatch Groups
当我们向监听多个异步任务全部完成的时候,就需要为每个任务添加BOOL点判断位, 这个做非常冗余,不友好, 这时我们需要使用dispatch group 来解决, 它可以同步或异步的在完成组内的所有任务的时候发出通知. API 有两种通知方式:dispatch_group_wait 会阻塞当前的线程,等待租内的所有任务都完成或者超时的时候发出通知, 这是同步的.
dispatch_group_notify 会给出一个异步的回调块,它不会阻塞所在的线程
// 异步执行任务 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), ^{ // 会等待两个线程全结束后, 汇总结果 });
dispatch_apply
当我们通过 for 循环添加一些任务到队列中的时候,如何才能提高添加速度呢, 我们可以使用dispatch_apply, 它可以异步执行循环内部的实现, 但是它本身是同步的方法, 需要等到循环完全结束后才返回.合适使用它才合适?自定义串行队列. 不要再这里使用, 串行队列会使它无效
主队列. 还是一样, 串行队列使它无效
并行队列. 可以很好的使用它, 尤其是我们向监控任务的进度.
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t i) { // 循环执行 10 次 });
dispatch_source
它可以简单轻松的监听系统事件,用户自定义事件等,它可以在任何的队列上传递并处理回调事件, 也可以执行挂起, 恢复操作, 默认创建后是挂起的.创建dispatch_source 会有很多种要监听的类型,比如:timer计时器的周期性通知事件
UNIX系统的信号通知
文件或端口的事件:读数据, 写数据, 文件被删除,移动,修改,重命名等.
进程的状态事件: 进程退出, 一个信号到达进程, 进程执行或分支
Mach
用户自定义的事件
创建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
相关文章推荐
- IOS多线程之GCD的一些常规用法
- 学习GCD的一些基本用法
- swift详解之十七-----------GCD的一些高级用法
- 关于GCD的一些用法
- android 中vector的用法 ,坑 ,怎么替代,关于这几方面的一些看法
- 【代码笔记】iOS-GCD用法
- sed的一些用法总结
- iOS xib关于Scroll View和View平分等其他控件的一些用法
- php中magic_quotes_gpc函数一些用法
- 网页中一些比较隐蔽的用法
- C++ MFC Tab Control 控件的一些用法
- jquery的一些用法 有用的用法。
- 关于sqlplus用法的一些总结
- Eclipse Debug的一些用法
- css中的一些选择器的用法总结
- Angular.js指令学习中一些重要属性的用法教程
- meta的一些用法
- Eclipse 工作集的用法 用法的一些补充
- 变参函数一些用法
- BigInteger类的一些用法