GCD
GCD
  任务和队列
    任务
      同步执行（sync）
        同步添加任务到指定的队列中，在添加的任务执行结束之前，会一直等待，直到队列里面的任务完成之后再继续执行。
        只能在当前线程中执行任务，不具备开启新线程的能力。
      异步执行（async）
        异步添加任务到指定的队列中，它不会做任何等待，可以继续执行任务。
        可以在新的线程中执行任务，具备开启新线程的能力。但是并不一定开启新线程。这跟任务所指定的队列类型有关。
    队列
      串行队列
        每次只有一个任务被执行。让任务一个接着一个地执行。（只开启一个线程，一个任务执行完毕后，再执行下一个任务）
      并行队列
        可以让多个任务并发（同时）执行。（可以开启多个线程，并且同时执行任务），并发队列 的并发功能只有在异步（dispatch_async）函数下才有效
    使用步骤
      创建一个队列（串行队列或并发队列）
        普通队列
          可以使用dispatch_queue_create来创建队列，需要传入两个参数，第一个参数表示队列的唯一标识符，用于 DEBUG，可为空，Dispatch Queue 的名称推荐使用应用程序 ID 这种逆序全程域名；第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 表示串行队列，DISPATCH_QUEUE_CONCURRENT 表示并发队列。
// 串行队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
        主队列
          所有放在主队列中的任务，都会放到主线程中执行。
可使用dispatch_get_main_queue()获得主队列。
        全局并发队列
          可以使用dispatch_get_global_queue来获取。需要传入两个参数。第一个参数表示队列优先级，一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二个参数暂时没用，用0即可。
      将任务追加到任务的等待队列中，
然后系统就会根据任务类型执行任务（同步执行或异步执行）
        同步执行 + 并发队列
          没有开启新线程，串行执行任务
        异步执行 + 并发队列
          有开启新线程，并发执行任务
        同步执行 + 串行队列
          当前串行队列下
            互相等待，死锁崩溃
          其他队列下
            没有开启新线程，串行执行任务
        异步执行 + 串行队列
          有开启新线程(1条)，串行执行任务
        同步执行 + 主队列
          主线程
            互相等待，死锁崩溃
          其他线程
            没有开启新线程，串行执行任务
        异步执行 + 主队列
          没有开启新线程，串行执行任务
  其他方法
    dispatch_barrier_async
      先执行完栅栏前面的操作，再执行栅栏操作，最后再执行栅栏后边的操作。
    dispatch_after
      延时执行
    dispatch_once
      一次性代码
    dispatch_apply
      快速迭代方法
    dispatch_group
      队列组
    dispatch_semaphore
      信号量
  简介
    Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法。
* GCD 可用于多核的并行运算
* GCD 会自动利用更多的 CPU 内核（比如双核、四核）
* GCD 会自动管理线程的生命周期（创建线程、调度任务、销毁线程）
* 程序员只需要告诉 GCD 想要执行什么任务，不需要编写任何线程管理代码
任务就是执行操作的意思，换句话说就是你在线程中执行的那段代码。
在 GCD 中是放在 block 中的。执行任务有两种方式：同步执行（sync）和异步执行（async）。
两者的主要区别是：是否等待队列的任务执行结束，以及是否具备开启新线程的能力。
这里的队列指执行任务的等待队列，即用来存放任务的队列。队列是一种特殊的线性表，采用 FIFO（先进先出）的原则，即新任务总是被插入到队列的末尾，而读取任务的时候总是从队列的头部开始读取。每读取一个任务，则从队列中释放一个任务。队列的结构可参考下图：
在 GCD 中有两种队列：串行队列和并发队列。两者都符合 FIFO（先进先出）的原则。两者的主要区别是：执行顺序不同，以及开启线程数不同。
通常我们会用 for 循环遍历，但是 GCD 给我们提供了快速迭代的函数dispatch_apply。dispatch_apply按照指定的次数将指定的任务追加到指定的队列中，并等待全部队列执行结束。
/**
* 快速迭代方法 dispatch_apply
*/
- (void)apply {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(6, queue, ^(size_t index) {
NSLog(@"%zd---%@",index, [NSThread currentThread]);
});
NSLog(@"apply---end");
}
* 调用队列组的 dispatch_group_async 先把任务放到队列中，然后将队列放入队列组中。或者使用队列组的 dispatch_group_enter、dispatch_group_leave 组合 来实现
dispatch_group_async。
- (void)group1 {
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"group---end");
});
}
- (void)group2 {
dispatch_group_t dispatchGroup = dispatch_group_create();
dispatch_group_enter(dispatchGroup);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"1---%@",[NSThread currentThread]);
dispatch_group_leave(dispatchGroup);
});
dispatch_group_enter(dispatchGroup);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2---%@",[NSThread currentThread]);
dispatch_group_leave(dispatchGroup);
});
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
NSLog(@"group---end");
});
}
* 调用队列组的 dispatch_group_notify 回到指定线程执行任务。或者使用 dispatch_group_wait 回到当前线程继续向下执行（会阻塞当前线程）。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);