CGD 详解

CGD 详解1 0 GCD 概要 1 1 什么是 GCD Grand Central Dispatch GCD 是一种异步执行任务的技术之一 一般将应用程序中记述的线程管理用的代码在系统级中实现 是 Apple 开发的一个多核编程的较新的解决方法 它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统 它是一个在线程池模式的基础上执行的并行任务

大家好,我是讯享网,很高兴认识大家。

1.0 GCD 概要

1.1 什么是 GCD

Grand Central Dispatch(GCD)是一种异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。

是Apple开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并行任务。在Mac OS X 10.6雪豹中首次推出,也可在IOS 4及以上版本使用。

1.2 用 GCD 的好处

  • GCD可用于多核的并行运算
  • GCD会自动利用更多的CPU内核(比如双核、四核)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

1.3 相关概念

  • 任务
    指你将要执行的那段代码。比如一个耗时操作。在 GCD 中,一个任务需要添加到一个队列中去执行。
    任务的执行又分为同步(sysc)执行和异步(asysc)执行。异步执行一定会开启线程,同步执行一定不会开启新线程。
    任务的种类 说明 对应函数
    同步任务 不开启线程,只在当前线程中执行 dispatch_sync(queue, ^{})
    异步任务 开启新线程 dispatch_async(queue, ^{})
  • 队列(Dispatch Queue)
    指执行处理的等待队列。应用程序编程人员通过 dispatch_asysnc 函数等 API,在 Block 语法中记述想执行的处理并将其追加到 Dispatch Queue 中。Dispatch Queue 按照追加的顺序(先进先出 FIFO,first-in-first-out)执行处理。
    在执行处理时存在两种 DispatchQueue,一种是等待现在执行中处理的 Serial Dispatch Queue,另一种是不等待现在执行中处理的 Concurrent Dispatch Queue。
Dispatch Queue 的种类 说明
Serial Dispatch Queue 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
Concurrent Dispatch Queue 可以让多个任务并行(同时)执行(自动开启多个线程同时执行任务)

2.0 GCD 基本使用步骤

2.1 步骤

2.2 队列的创建

// 串行队列的创建方法 dispatch_queue_t queue= dispatch_queue_create("id", DISPATCH_QUEUE_SERIAL); // 并行队列的创建方法 dispatch_queue_t queue= dispatch_queue_create("id", DISPATCH_QUEUE_CONCURRENT); // 主队列的创建方法(串行) dispatch_queue_t queue = dispatch_get_main_queue(); // 全局队列的创建方法(并行) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 第一个参数为优先级,第二个不讨论,传0即可。

讯享网

2.3 任务的创建

讯享网// 同步执行任务创建方法 dispatch_sync(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 存放任务代码 }); // 异步执行任务创建方法 dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 存放任务代码 }); 

2.4 组合方式以及结果

任务 串行队列 并行队列 主队列
sysc 同步任务 不开启线程,串行执行 不开启线程,串行执行 死锁
asysc 异步任务 开启一个线程,串行执行 开新线程,并行执行 在主线程串行执行

3.0 GCD 的 基本使用

3.1 dispatch_once 一次性执行

static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 待执行代码,该代码在程序的生命周期中只执行一次 }); 

3.2 dispatch_after

讯享网dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 待执行代码 ,60秒后开始执行 });

3.3 定时器

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC, 0 * NSEC_PER_SEC); dispatch_source_set_event_handler(timer, ^{ // 待执行代码 ,每隔60秒执行一次 }); dispatch_resume(timer);

3.4 dispatch_group

3.5 dispatch_barrier

提供一个栅栏方法,用于实现在当前队列同步执行一个block,主要用于多个异步并发任务的分段处理,可以很好的替代dispatch_group

3.5.1 dispatch_barrier_async

讯享网- (void)viewDidLoad { [super viewDidLoad]; dispatch_queue_t queue1 = dispatch_queue_create("test1", DISPATCH_QUEUE_CONCURRENT); NSLog(@"current task"); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"A %ld %@", i,[NSThread currentThread]); } }); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"B %ld %@", i,[NSThread currentThread]); } }); dispatch_barrier_async(queue1, ^{ NSLog(@"栅栏函数"); }); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"C %ld %@", i,[NSThread currentThread]); } }); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"D %ld %@", i,[NSThread currentThread]); } }); NSLog(@"next task"); }

打印结果:


讯享网

2018-01-13 16:26:57.+0800 ServiceTest[40341:] current task 2018-01-13 16:26:57.+0800 ServiceTest[40341:] next task 2018-01-13 16:26:57.+0800 ServiceTest[40341:] B 0 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] A 0 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] A 1 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] B 1 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] A 2 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] B 2 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] A 3 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] B 3 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] A 4 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] B 4 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] 栅栏函数 2018-01-13 16:26:57.+0800 ServiceTest[40341:] D 0 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] C 0 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] C 1 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] D 1 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] D 2 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] C 2 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] D 3 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] C 3 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] D 4 <NSThread: 0xba00>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:26:57.+0800 ServiceTest[40341:] C 4 <NSThread: 0xc0>{ 
  
    
  number = 4, name = (null)}

3.5.2 dispatch_barrier_sync

讯享网- (void)viewDidLoad { [super viewDidLoad]; dispatch_queue_t queue1 = dispatch_queue_create("test1", DISPATCH_QUEUE_CONCURRENT); NSLog(@"current task"); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"A %ld %@", i,[NSThread currentThread]); } }); dispatch_sync(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"B %ld %@", i,[NSThread currentThread]); } }); dispatch_barrier_async(queue1, ^{ NSLog(@"栅栏函数"); }); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"C %ld %@", i,[NSThread currentThread]); } }); dispatch_async(queue1, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"D %ld %@", i,[NSThread currentThread]); } }); NSLog(@"next task"); } 

打印结果

2018-01-13 16:30:24.+0800 ServiceTest[40377:] current task 2018-01-13 16:30:24.+0800 ServiceTest[40377:] B 0 <NSThread: 0xc0>{ 
  
    
  number = 1, name = main} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] A 0 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] B 1 <NSThread: 0xc0>{ 
  
    
  number = 1, name = main} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] A 1 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] B 2 <NSThread: 0xc0>{ 
  
    
  number = 1, name = main} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] A 2 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] B 3 <NSThread: 0xc0>{ 
  
    
  number = 1, name = main} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] A 3 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] B 4 <NSThread: 0xc0>{ 
  
    
  number = 1, name = main} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] A 4 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] 栅栏函数 2018-01-13 16:30:24.+0800 ServiceTest[40377:] next task 2018-01-13 16:30:24.+0800 ServiceTest[40377:] C 0 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] D 0 <NSThread: 0xd80>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] C 1 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] D 1 <NSThread: 0xd80>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] C 2 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] D 2 <NSThread: 0xd80>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] C 3 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] D 3 <NSThread: 0xd80>{ 
  
    
  number = 4, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] C 4 <NSThread: 0x0>{ 
  
    
  number = 3, name = (null)} 2018-01-13 16:30:24.+0800 ServiceTest[40377:] D 4 <NSThread: 0xd80>{ 
  
    
  number = 4, name = (null)} 

3.6 dispatch_semaphore

信号量是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待。当一个信号量被信号通知,其计数会被增加。当一个线程在一个信号量上等待时,线程会被阻塞(如果有必要的话),直至计数器大于零,然后线程会减少这个计数。
  在GCD中有三个函数是semaphore的操作,分别是:
  dispatch_semaphore_create   创建一个semaphore
  dispatch_semaphore_signal   发送一个信号
  dispatch_semaphore_wait    等待信号
  简单的介绍一下这三个函数,第一个函数有一个整形的参数,我们可以理解为信号的总量,dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1,根据这样的原理,我们便可以快速的创建一个并发控制来同步任务和有限资源访问控制。
  还有这么一个比喻:停车场剩余4个车位,那么即使同时来了四辆车也能停的下。如果此时来了五辆车,那么就有一辆需要等待。信号量的值就相当于剩余车位的数目,dispatch_semaphore_wait函数就相当于来了一辆车,dispatch_semaphore_signal 就相当于走了一辆车。停车位的剩余数目在初始化的时候就已经指明了(dispatch_semaphore_create(long value)),调用一次dispatch_semaphore_signal,剩余的车位就增加一个;调用一次dispatch_semaphore_wait剩余车位就减少一个;当剩余车位为0时,再来车(即调用dispatch_semaphore_wait)就只能等待。有可能同时有几辆车等待一个停车位。有些车主没有耐心,给自己设定了一段等待时间,这段时间内等不到停车位就走了,如果等到了就开进去停车。而有些车主就像把车停在这,所以就一直等下去。

讯享网// 一个简单的例子 - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"current task"); //创建一个并行队列 dispatch_queue_t queque = dispatch_queue_create("GoyakodCreated", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); //异步执行 dispatch_async(queque, ^{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{ // 耗时操作 NSLog(@"耗时操作"); dispatch_semaphore_signal(semaphore); }); }); // 如果不添加信号量的限制,会先执行下面的打印代码 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"执行完了耗时操作,做进一步处理"); NSLog(@"next task"); }

打印结果

2018-01-13 17:28:26.+0800 ServiceTest[40871:] current task 2018-01-13 17:28:31.+0800 ServiceTest[40871:] 耗时操作 2018-01-13 17:28:31.+0800 ServiceTest[40871:] 执行完了耗时操作,做进一步处理 2018-01-13 17:28:31.+0800 ServiceTest[40871:] next task

3.7 快速迭代方法 dispatch_apply

通常我们会用for循环遍历,但是GCD给我们提供了快速迭代的方法dispatch_apply,使我们可以同时遍历。比如说遍历0~5这6个数字,for循环的做法是每次取出一个元素,逐个遍历。dispatch_apply可以同时遍历多个数字。

讯享网- (void)viewDidLoad { [super viewDidLoad]; dispatch_queue_t queue1 = dispatch_queue_create("test1", DISPATCH_QUEUE_CONCURRENT); // 注意,这里如果是DISPATCH_QUEUE_SERIAL 串行队列,结果不开线程,串行遍历 NSLog(@"current task"); dispatch_apply(6, queue1, ^(size_t i) { NSLog(@"E %ld %@", i,[NSThread currentThread]); }); NSLog(@"next task");

打印结果

2018-01-13 16:39:24.+0800 ServiceTest[40456:] current task 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 0 <NSThread: 0xf140>{number = 1, name = main} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 1 <NSThread: 0x0>{number = 3, name = (null)} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 2 <NSThread: 0x0>{number = 4, name = (null)} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 3 <NSThread: 0x0>{number = 5, name = (null)} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 4 <NSThread: 0xf140>{number = 1, name = main} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] E 5 <NSThread: 0x0>{number = 3, name = (null)} 2018-01-13 16:39:24.+0800 ServiceTest[40456:] next task
小讯
上一篇 2025-02-18 11:14
下一篇 2025-03-04 16:41

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/25333.html