GCD的理解与使用
来源:互联网 发布:linux arping 编辑:程序博客网 时间:2024/06/06 01:30
GCD的理解与使用
在这之前先很通俗理解几个基本的概念:
队列(queue):队列是相对任务而言的,队列是一个存放任务的地方。
任务(task):需要做啥?把需要做的事情“打包”成一个任务,再塞入自己所能“掌握”的队列里面。
调度:对列有了,里面也有任务了。那么任务需要在什么时候被开始?
先了解一下队列的四种优先级
/** * 全局队列的四种优先级 * * DISPATCH_QUEUE_PRIORITY_HIGH * DISPATCH_QUEUE_PRIORITY_DEFAULT * DISPATCH_QUEUE_PRIORITY_LOW * DISPATCH_QUEUE_PRIORITY_BACKGROUND * 被设置成后台级别的队列,它会等待所有比它级别高的队列中的任务执行完成或者CPU空闲的时候才会执行自己的任务。 * 例如磁盘的读写操作非常耗时,如果我们不需要立即获取到磁盘的数据,我们可以把读写任务放到后台队列中,这样读写任务只会在恰当的时候去执行, * 从而让程序更加有效率。 */
#pragma mark - 只执行一次的函数,多用于单例化- (void)dispatchOnceToken { static dispatch_once_t onceToken; for (NSInteger i = 0; i < 10; i++) { /// 只会在i == 0的时候进入一次,并且推出再进来,NSLog(@"%ld",i);永远不会再走了 dispatch_once(&onceToken, ^{ NSLog(@"%ld",i); }); }}
主要用于单例化。
#pragma mark - 同步和异步- (void)asycnAction { weakSelf(self); /// 异步全局队列,并塞入一个任务 dispatch_async(dispatch_get_global_queue(0, 0), ^{ /// 做一个延迟操作 sleep(5); /// 回到主线程(主线程默认是一个串行队列,所以这边用sync和async的效果是一样的) /** * 这边如果都使用weakself就不会产生强引用,退出当前VC之后立马dealloc * 但是延迟操作之后,该任务还是会被执行,但是此时weakself为nil,所有任务表现为无效 * * 如果其中一个使用self,便会产品强引用 */ dispatch_sync(dispatch_get_main_queue(), ^{ [weakSelf printNum:@"123"]; }); dispatch_async(dispatch_get_main_queue(), ^{ /// 这边使用self会产生强引用,退出当前VC之后并不会立刻dealloc [self printNum:@"456"]; }); });}
其实,主线程(main)就是一个串行队列,也是UI的绘制线程,所以保证main线程的通畅是“代码”需要考虑深究的。
#pragma mark - 自定义队列- (void)customQueue { /// 串行队列 /// PS:dispatch_queue_attr_t设置成NULL的时候默认代表串行。 dispatch_queue_t serialQueue; serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL); /// 并发队列 dispatch_queue_t concurrentQueue; concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);}
自定义队列,可以在需要手动管理的时候,通过自定义的队列名称,获取到相关的队列,进行挂起等操作。
#pragma mark - 挂起、恢复队列- (void)suspendAndResumeQueue { dispatch_queue_t globaleQueue = dispatch_get_global_queue(0, 0); /// 挂起队列。挂起操作并不会对已经开始执行的任务起作用,仅会阻止队列中还未开始的任务 dispatch_suspend(globaleQueue); /// 恢复队列 dispatch_resume(globaleQueue);}
要慎用线程的挂起操作。
#pragma mark - 信号量的使用/** * 信号量的作用是控制多个任务对有限数量资源的访问。 * 简单来说就是,如果你创建一个有着两个资源的信号量,那么最多同时只能有两个线程可以访问临界区,其它想使用资源的线程必须在FIFO队列里面等待 */- (void)dispatchSemaphores { weakSelf(self); /// 创建一个信号量 dispatch_semaphore_t t = dispatch_semaphore_create(1); dispatch_queue_t concurrentQueue1; concurrentQueue1 = dispatch_queue_create("com.example.ConcurrentQueue1", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t concurrentQueue2; concurrentQueue2 = dispatch_queue_create("com.example.ConcurrentQueue2", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t concurrentQueue3; concurrentQueue3 = dispatch_queue_create("com.example.ConcurrentQueue3", DISPATCH_QUEUE_CONCURRENT); /** 需要在每一个队列里面通过dispatch_semaphore_wait这个来等待信号量*/ dispatch_async(concurrentQueue1, ^{ /// 避免数据的抢夺 dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER); for (NSInteger i = 0; i < 10; i++) { NSLog(@"第一队列:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第一队列任务结束了"]; dispatch_semaphore_signal(t); }); }); dispatch_async(concurrentQueue2, ^{ dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER); for (NSInteger i = 0; i < 10; i++) { NSLog(@"第二队列_____:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第二队列:任务结束了"]; dispatch_semaphore_signal(t); }); }); dispatch_async(concurrentQueue3, ^{ dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER); for (NSInteger i = 0; i < 10; i++) { NSLog(@"第三队列——————:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第三队列:任务结束了"]; dispatch_semaphore_signal(t); }); });}下面是打印结果:2017-07-03 15:17:55.109 Functions[13737:1176065] 第一队列:i=02017-07-03 15:17:55.109 Functions[13737:1176065] 第一队列:i=12017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=22017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=32017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=42017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=52017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=62017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=72017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=82017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=92017-07-03 15:17:55.126 Functions[13737:1175989] 第一队列任务结束了2017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=02017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=12017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=22017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=32017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=42017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=52017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=62017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=72017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=82017-07-03 15:17:55.128 Functions[13737:1176068] 第二队列_____:i=92017-07-03 15:17:55.128 Functions[13737:1175989] 第二队列:任务结束了2017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=02017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=12017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=22017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=32017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=42017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=52017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=62017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=72017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=82017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=92017-07-03 15:17:55.129 Functions[13737:1175989] 第三队列:任务结束了可以把每一个i想象成几个线程共享数据的使用,每一次调用都是一次使用,根据打印结果可以看出,不同队列之间,不会在同一时刻同时调用打印i。
其实,可以通过信号量或者干脆点,直接用串行(异步相对于main的串行队列)来避免资源的抢夺。
#pragma mark - Dispatch Groups的使用/** * 是一个可以阻塞线程直到一个或多个任务完成的一种方式 * 在那些需要等待任务完成才能执行某个处理的时候,可以使用这个方法 */- (void)dispatchGroup { weakSelf(self); dispatch_queue_t concurrentQueue1; concurrentQueue1 = dispatch_queue_create("com.example.ConcurrentQueue1", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t concurrentQueue2; concurrentQueue2 = dispatch_queue_create("com.example.ConcurrentQueue2", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t concurrentQueue3; concurrentQueue3 = dispatch_queue_create("com.example.ConcurrentQueue3", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t groupQueue = dispatch_group_create(); dispatch_group_async(groupQueue, concurrentQueue1, ^{ for (NSInteger i = 0; i < 1000; i++) { NSLog(@"第一队列:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第一队列任务结束了"]; }); }); dispatch_group_async(groupQueue, concurrentQueue2, ^{ for (NSInteger i = 0; i < 1000; i++) { NSLog(@"第二队列_____:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第二队列:任务结束了"]; }); }); dispatch_group_async(groupQueue, concurrentQueue3, ^{ for (NSInteger i = 0; i < 1000; i++) { NSLog(@"第三队列——————:i=%ld",i); } dispatch_async(dispatch_get_main_queue(), ^{ /// 使用完数据,发送一个信号 [weakSelf printNum:@"第三队列:任务结束了"]; }); }); dispatch_group_async(groupQueue, dispatch_get_global_queue(0, 0), ^{// dispatch_async(dispatch_get_global_queue(0, 0), ^{// for (NSInteger i = 0; i < 100000; i++) {// NSLog(@"全局队列——————:i=%ld",i);// }// }); /// 这种情况下,dispatch_group_notify会一直等待它完成,但是如果是上面那种情况,内部再开一个异步并行的,dispatch_group_notify就不会等待,或者说捕捉不到该等待,所以对于网络请求(基本都是异步请求的),是不可以同时放几个请求在group下面,用来等待全部完成的时候refreshUI的 for (NSInteger i = 0; i < 100000; i++) { NSLog(@"全局队列——————:i=%ld",i); } }); dispatch_group_notify(groupQueue, dispatch_get_main_queue(), ^{ NSLog(@"三个任务都完成了"); });}
对于多个任务,可以开启多个异步并行队列,同时开启多个任务(如果CPU支持的话),用dispatch_group_notify来等待最终的结果。但是不可以在单个队列内部再开启一个异步并行队列(比如UI的刷新同时依赖几个请求的完成),dispatch_group_async是无法捕捉到这样的结束的。
以上就是我对GCD的基本了解以及GCD的常用API,如有错误,希望不吝指正,谢谢!
阅读全文
0 0
- GCD的理解与使用
- GCD 的使用与理解(1)
- GCD的使用与理解(2)
- GCD dispatch_async 与dispatch_sync 的理解
- GCD 的简单理解
- GCD的一点理解
- GCD--我的理解
- GCD的理解
- GCD 的理解
- GCD的深入理解
- GCD的理解
- GCD死锁的理解
- GCD的一点理解
- 针对GCD的理解
- GCD Blocks与Dispatch Queue的使用
- iOS中多线程与GCD的使用
- GCD的介绍与使用(三)
- GCD的介绍与使用(四)
- AWS-G2.2xlarge的Redhat7.2上安装Nvidia驱动、CUDA7.5和cudnn4.0
- python import用法
- HBuilder自定义dialog
- codeforces 822 C Hacker, pack your bags!
- standardUserDefaults 的使用
- GCD的理解与使用
- hdu_round1-1007 吃巧克力(计算几何)
- Firefox关闭GET请求到detectportal.firefox.com网站的方法
- 页面中多组切换按钮— 事件不同
- angularjs1.*返回跳转到上一页代码配置
- 朋友圈那个随便辞职的年轻人,后来活成了什么样?
- Android的插件化和组件化
- Web前端工程师知识体系大全,Web前端入门基础体系
- gradle使用基础