1. GCD简介
 
     GCD为我们编写代码提供了绝佳的体验。他是苹果公司在多核心设备上实现多线程充分利用多核优势提供的解决方案,在很多技术中如 RunLoop GCD 都扮演了重要的角色。GCD全称​Grand Central Dispatch,直译为调度组中心,完全基于​C语言编写的,不需要管理线程,线程管理完全交给GCD。把线程想象成火车,我们只需要提交我们的运送任务,GCD会帮助我们在合适的火车上运送任务。多线程编程变得的如此简单。但GCD是纯c 的代码,没有对象的概念,学习GCD你可以忘记封装,继承,多态等概念。
 
GCD提供给我们的优势
 
易用​: GCD比之​thread​更加的简单易用,由于GCD基于​work unit而非像​thread那样基于运算,所以GCD可以控制诸如等待任务结束,监视文件描述周期执行代码以及工作挂起等任务。基于block的血统导致它极其简单的在不同代码之间传递上下文。
 
效率:GCD被实现的如此轻量级与优雅,使得他在很多地方比之专门创建消耗资源的线程更实用且快速。这关系到易用性:导致GCD易用的原因一部分在于你可以不用担心太多效率的问题儿仅仅的实用他就好了
 
性能:GCD自动根据系统负载来增减线程的数量,这就减少了上下文切换以及增加了计算效率
 
2. dispatch queue
 
GCD中的一个重要组成的部分就是队列,我们把各种任务提交给队列,队列根据它本身的类型以及当前系统的状态,添加到不同的线程中执行任务。线程的创建和管理都有GCD本身完成,不需要我们的参与。系统提供了很多定义好的队列:只管理主线程的main_queue和全局并行的globle_queue。同时我们也可以定义自己的队列queue。
 
2.1 queue的种类
 
并行queue :可以在多个线程并行,多个任务可以同时执行
串行queue:所有的线程串行,或者只有一个线程,任务一次执行
 
2.2创建自定义的​queue
 
queue的类型为​dispatch_queue_t
创建函数为dispatch_queue_create()
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
 
  • 第一个参数代表queue的名字,注意是char型指针,而非NSString
  • 第二个参数代表queue的类型
 
  • ​DISPATCH_QUEUE_SERIAL 表示串行的queue
  • ​DISPATCH_QUEUE_CONCURRENT 表示并行的queue
 
2.2​获得预定义的queue
 
除自己定义queue以外,我们可以使用系统预定义的queue,包括两种。
一:获取全局并发的queue
 
获取全局的一个queue,该队列的种类是并行queue,也就是说我们可以直接交给这个queue,任务会在非主线程的其他线程内执行
dispatch_get_global_queue(long identifier, unsigned long flags);
 
  • 第一个参数表示queue的优先级,有四种优先级
 
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
 
  • 第二个参数没有意义
 
二:获取管理主线程的queue
 
     main queue的种类属于串行队列,提交给该queue的任务,会加入到主线程之中,提交给main queue 的任务可能不会立马被执行,而是在主线程的RinLoop检测到有dispatch提交过来的任务时才会被执行
 
·dispatch_get_main_queue()
 
2.3 queue的内存管理
 
     ARC环境下,不需要手动编写代码。非ARC环境下需要使用​dispatch_retain()和dispatch_release()管理queue的引用计数。原则如同NSObject对象,计数为0时销毁queue。
 
dispatch_queue_t q_1 = dispatch_queue_create("task3.queue.
1",DISPATCH_QUEUE_SERIAL);
dispatch_release(q_1);
 
3.提交任务
 
     提交任务分为两种方式,异步和同步。同步提交任务,会等待任务完成。异步不需要等待任务完成。即通过提交会卡死当前线程。
 
3.1同步提交
 
同步提交函数为dispatch_sync(),​两个参数:
 
  • 第一个参数表示提交到queue
  • 第一个参数表示任务详情
 
     这里用block的方式描述一个任务,原因很简单,Block也是纯C实现的,而平时使用的Invocation或者target+selector方式都是面向对象的。
注意:同步提交任务后,先执行完block,然后dispatch_sync()返回,这时候如果同步提交的任务过场会导致主线程卡死。
 
3.2异步提交
异步提交函数为dispatch_async(),两个参数:
第一个参数表示提交到的queue
第二个参数表示任务详情
异步提交任务后,dispatcha_async()函数直接返回,无需等待block执行结束,不会导致主线程卡死。
 
3.3同时提交多次任务
     同时提交多个任务给queue的函数很简单:
dispatch_apply(size_t iterations, dispatch_queue_t queue,void (^block)(size_t));
三个参数分别是任务数,目标queue,任务描述
 
     这里注意描述任务的block灰重复多次使用,每次会给我们一个参数,表示任务次序。多个任务的执行顺序取决于添加队列queue的形式,如果目标queue是串行的,那么任务会依次执行,如果queue是并行的,那么任务会并发的执行,打印的顺序就会被打乱。
 
3.4 死锁
     同步提交在某种情况下回造成死锁,即卡死。
示例1:
dispatch_queue_t mainQ = dispatch_get_main_queue();
 
     dispatch_sync(mainQ, ^{
               NSLog(@"----");
     });
     NSLog(@"OK");
 
示例2:
 
     dispatch_queue_t q_1 = dispatch_queue_create("task3.queue. 1",DISPATCH_QUEUE_SERIAL);
dispatch_async(q_1, ^{
 
     NSLog(@"current is in q_1");
     // q_1 blcok q_1 q_1 dispatch_sync
          block block dispatch_sync
          dispatch_sync(q_1, ^{
          NSLog(@"this is sync ");
     });
     NSLog(@"this is sync ????");
     });
 
     综合上面两个示例代码,结论显而易见:在一个串行队列执行的代码中,如果向此队列同步提交一个任务,会造成死锁。为了避免出现死锁的情况,要求我们避免在串行队列中同步提交任务给本身的队列。
 
4.queue的暂停和继续
 
     我们可以使用dispatch_suspend函数暂停一个queue以阻止它执行尚未执行的block对象,使用dispatch_resume函数继续dispatch queue。挂起和继续是异步的,而且只在执行block之间(比如在执行一个新的block之前或之后)生效。挂起一个queue不会导致正在执行的block停止。特别强调,需要我们保证挂起队列和重启队列的函数承兑调用。
 
     在非ARC中使用时需要注意:调用dispatch_suspend会增加queue的引用计数,调用dispatch_resume则减少queue的引用计数。当引用计数大于0时,queue就保持挂起状态。因此你必须对应的调用suspend和resume函数。
 
5.Dispatch Group
 
     什么是dispatch group,就像我们在NSOperation中添加依赖一样,如果我们一个任务需要等待其他一些任务完成才能执行时,我们使用dispatch group是最轻松的解决方式。
 
5.1设置任务执行顺序
 
     GCD设置任务执行顺序是通过Dispatch Group实现的。我们以吃火锅为例:
 
  • 首先创建group与任务队列
  • dispatch_group_t group = dispatch_group_create();
  • dispatch_queue_t globleQ = dispatch_get_global_queue(0, 0);
  • 提交任务,并且把任务添加到group中
  • dispatch_group_async(group, globleQ, ^{});
 
注意:
     提交任务到group时没有同步提交的,只有异步提交
     提交最终任务到group,同样为异步提交,
     dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{});
 
5.2时间延迟
 
     dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
     使当前线程堵塞,一直等待group所有任务结束:
     dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (300 *NSEC_PER_S EC));
     dispatch_group_wait(group, time); NSLog(@"");
     也可以自定超时时间,只等待一定的时间之后group内的任务没有执行的直接停止-
 
posted on 2016-01-16 22:00  <孙涛>  阅读(386)  评论(0)    收藏  举报