GCD

 任务和队列

  • 任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的。执行任务有两种方式:同步执行异步执行。两者的主要区别是:是否具备开启新线程的能力。

    1. 同步执行(sync):只能在当前线程中执行任务,不具备开启新线程的能力
    • 必须等待当前语句执行完毕,才会执行下一条语句
    • 不会开启线程
    • 在当前主线程执行 block 的任务
    • dispatch_sync(queue, block);
    1. ** 异步执行(async)**:可以在新的线程中执行任务,具备开启新线程的能力
    • 不用等待当前语句执行完毕,就可以执行下一条语句
    • 会开启线程执行 block 的任务
    • 异步是多线程的代名词
    • dispatch_async(queue, block);
  • 队列:这里的队列指任务队列,即用来存放任务的队列。队列是一种特殊的线性表,采用FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。在GCD中有四种队列:串行队列并发队列主队列全局队列

    1. 串行队列(Serial Dispatch Queue):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

      • 一次只能"调度"一个任务
      • dispatch_queue_create("queue", NULL);
        或者dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    2. 并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务),

      • 一次可以"调度"多个任务
      • 并发功能只有在异步(dispatch_async)函数下才有效
      • dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    3. 主队列

      • 专门用来在主线程上调度任务的队列
      • 不会开启线程
      • 在主线程空闲时才会调度队列中的任务在主线程执行
      • dispatch_get_main_queue();
    4. 全局队列

      • 执行过程和并发队列一致,参考并发队列
      • dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  小结:在以后的使用中,记住下面的就可以了!

  串行队列同步执行不会开辟线程,所有block任务之间是同步执行的。

  串行队列异步执行仅会开辟一个(除主线程外)新的线程,所有block任务之间是同步(按顺序)执行的。

  并发队列同步执行和串行队列同步执行一样,都不会开辟新线程,block任务之间是同步执行的。

  并发队列异步执行结果中看到开辟了多个线程,并且执行顺序也不是顺序执行。

  1. 开不开线程由执行任务的函数决定
  • 异步开,异步是多线程的代名词
  • 同步不开
  1. 开几条线程由队列决定
  • 串行队列开一条线程(GCD会开一条,NSOperation Queue最大并发数为1时也可能开多条)
  • 并发队列开多条线程,具体能开的线程数量由底层线程池决定
- (void)testGCD{
    //任务:同步、异步     队列:串行、并发
    
    /***************** 队列的创建方法 ********************/
    //dispatch_queue_create创建队列
    //第一个参数:唯一标识符(自定义)
    //第二个参数:区分串行、并行
    //串行(DISPATCH_QUEUE_SERIAL)并行(DISPATCH_QUEUE_CONCURRENT)
    dispatch_queue_t queue01 = dispatch_queue_create("chuan.net", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue02 = dispatch_queue_create("bing.net", DISPATCH_QUEUE_CONCURRENT);
    
    //主队列也属于特殊的串行队列
    dispatch_queue_t queue03 = dispatch_get_main_queue();
    
    //全局并发队列  第一个参数:优先级  第二个参数:暂时没用
    dispatch_queue_t queue04 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    /**************** 任务的创建方法 *****************/
    dispatch_sync(queue01, ^{
       //同步执行任务
    });
    
    dispatch_async(queue01, ^{
       //异步执行任务
    });
    
    /*************************************/
    /**
     任务和队列的组合方式有以下几种:
     1、同步执行+并发队列
     2、同步执行+串行队列
     
     3、异步执行+并发队列
     4、异步执行+串行队列
     
     5、同步执行+主队列
     6、异步执行+主队列
     
     同步执行不具备开启新线程的能力,同步任务需要等待队列的任务执行结束
     
     */
    
    /****************** 同步执行+并发队列 *******************/
    //特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务
    dispatch_queue_t queue11 = dispatch_queue_create("tong_bing.net", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue11, ^{
        NSLog(@"同步执行+并发队列--追加任务1");
    });
    dispatch_sync(queue11, ^{
        NSLog(@"同步执行+并发队列--追加任务2");
    });
    dispatch_sync(queue11, ^{
        NSLog(@"同步执行+并发队列--追加任务3");
    });
    NSLog(@"同步执行+并发队列--结束");
    
    
    /****************** 同步执行+串行队列 *******************/
    //特点:不会开启新线程,在当前线程执行任务。任务是串行,执行完一个,再执行下一个。
    dispatch_queue_t queue12 = dispatch_queue_create("tong_chuan.net", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue12, ^{
        NSLog(@"同步执行+串行队列--追加任务1");
    });
    dispatch_sync(queue12, ^{
        NSLog(@"同步执行+串行队列--追加任务2");
    });
    dispatch_sync(queue12, ^{
        NSLog(@"同步执行+串行队列--追加任务3");
    });
    NSLog(@"同步执行+串行队列--结束");
    
    /****************** 异步执行+并发队列 *******************/
    //特点:可以开启多个线程,任务交替(同时)执行。
    dispatch_queue_t queue13 = dispatch_queue_create("yi_bing.net", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue13, ^{
        NSLog(@"异步执行+并发队列--追加任务1");
    });
    dispatch_async(queue13, ^{
        NSLog(@"异步执行+并发队列--追加任务2");
    });
    dispatch_async(queue13, ^{
        NSLog(@"异步执行+并发队列--追加任务3");
    });
    NSLog(@"异步执行+并发队列--结束");
    
    /****************** 异步执行+串行队列 *******************/
    //特点:会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。
    dispatch_queue_t queue14 = dispatch_queue_create("yi_chuan.net", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue14, ^{
        NSLog(@"异步执行+串行队列--追加任务1");
    });
    dispatch_async(queue14, ^{
        NSLog(@"异步执行+串行队列--追加任务2");
    });
    dispatch_async(queue14, ^{
        NSLog(@"异步执行+串行队列--追加任务3");
    });
    NSLog(@"异步执行+串行队列--结束");
    
    /****************** 同步执行+主队列 *******************/
    //在不同线程中调用结果也是不一样,在主线程中调用会出现死锁,而在其他线程中则不会。
    
                /********** 主线程中调用 ********/
    //互相等待卡住不可行
    
    //其他线程
    [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
    
    /****************** 异步执行+主队列 *******************/
    //特点:只在主线程中执行任务,执行完一个任务,再执行下一个任务
    dispatch_queue_t queue16 = dispatch_get_main_queue();
    
    dispatch_async(queue16, ^{
        NSLog(@"异步执行+主队列--追加任务1");
    });
    dispatch_async(queue16, ^{
        NSLog(@"异步执行+主队列--追加任务2");
    });
    dispatch_async(queue16, ^{
        NSLog(@"异步执行+主队列--追加任务3");
    });
    NSLog(@"异步执行+主队列--结束");
    
    /*************** dispatch_after延时操作 ******************/
    //dispatch_after函数并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到主队列中。
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //2.0秒后一步追加任务代码到主队列,并开始执行
        NSLog(@"延时执行操作");
    });
    
    /******************** dispatch_once ************************/
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"一次性代码");
    });
    
    /***************** dispatch_apply快速迭代 *********************/
    //dispatch_apply按照指定次数将指定任务追加到指定的队列中,并等待全部队列执行结束。
    //如果是在串行队列中使用 dispatch_apply,那么就和 for 循环一样,按顺序同步执行。可这样就体现不出快速迭代的意义了。
    //无论是在串行队列,还是异步队列中,dispatch_apply 都会等待全部任务执行完毕,这点就像是同步操作,也像是队列组中的 dispatch_group_wait方法
    dispatch_queue_t queue21 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_apply(10, queue21, ^(size_t index) {
        NSLog(@"快速迭代==%zd",index);
    });
    
    /****************** dispatch_group队列组 ********************/
    //队列组中的任务执行完毕返回主线程:把任务放入队列中再放入队列组
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"队列组--追加任务1");
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"队列组--追加任务2");
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"队列组--回到主线程");
    });
    
    /****************** dispatch_group_wait ********************/
    //暂停当前线程(阻塞当前线程),等待指定的group中的任务执行完成后,才会往下继续执行。
    dispatch_group_t group23 = dispatch_group_create();
    dispatch_group_async(group23, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"队列组--追加任务3");
    });
    dispatch_group_async(group23, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"队列组--追加任务4");
    });
    //等待上面的任务全部完成后,会往下继续执行(会阻塞当前线程)
    dispatch_group_wait(group23, DISPATCH_TIME_FOREVER);
    
    /********** dispatch_group_enter、dispatch_group_leave **********/
    //ispatch_group_enter标志着一个任务追加到group,执行一次,相当于group中未执行完毕任务数+1
    //dispatch_group_leave标志着一个任务离开了group,执行一次,相当于group中未执行完毕任务数-1。
    //当group中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,以及执行追加到dispatch_group_notify中的任务。
    dispatch_group_t group24 = dispatch_group_create();
    dispatch_queue_t queue001 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(group24);
    dispatch_async(queue001, ^{
        NSLog(@"dispatch_group_enter追加任务1");
        dispatch_group_leave(group24);
    });
    
    dispatch_group_enter(group24);
    dispatch_async(queue001, ^{
        NSLog(@"dispatch_group_enter追加任务2");
        dispatch_group_leave(group24);
    });
    
    dispatch_group_notify(group24, dispatch_get_main_queue(), ^{
        NSLog(@"dispatch_group_enter主线程");
    });
    
    
    
}

- (void)syncMain{
    dispatch_queue_t queue15 = dispatch_get_main_queue();
    dispatch_sync(queue15, ^{
        NSLog(@"同步执行+主队列--追加任务1");
    });
    dispatch_sync(queue15, ^{
        NSLog(@"同步执行+主队列--追加任务2");
    });
    dispatch_sync(queue15, ^{
        NSLog(@"同步执行+主队列--追加任务3");
    });
    NSLog(@"同步执行+主队列--结束");
}

//栅栏方法
- (void)barrier{
    dispatch_queue_t queue = dispatch_queue_create("barrier.net", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"追加任务1");
    });
    dispatch_sync(queue, ^{
        NSLog(@"追加任务2");
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"栅栏函数--追加任务3");
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"追加任务4");
    });
    
}

- (void)semaphore{
    /*************** dispatch_semaphore信号量 ****************/
    //Dispatch Semaphore 提供了三个函数。
    //dispatch_semaphore_create:创建一个Semaphore并初始化信号的总量
    //dispatch_semaphore_signal:发送一个信号,让信号总量加1
    //dispatch_semaphore_wait:可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。
    dispatch_queue_t queue01 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(queue01, ^{
        dispatch_semaphore_signal(semaphore); //加1
        //操作
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//减1
    });
    
}
 
小结:
  • 并发队列同步执行和串行队列同步执行一样,都不会开辟新线程,block任务之间是同步执行的!
  • 并发队列异步执行结果中看到开辟了多个线程,并且执行顺序也不是顺序执行。因为异步开多线程的代名词,并发是开多条线程的代名词
  • 有多个线程,操作进来之后它会将这些队列安排在可用的处理器上,同时保证先进来的任务优先处理。
  • 以先进先出的方式,并发调度队列中的任务执行
  • 如果当前调度的任务是同步执行的,会等待任务执行完成后,再调度后续的任务
  • 如果当前调度的任务是异步执行的,同时底层线程池有可用的线程资源,会再新的线程调度后续任务的执行

 

原文地址:https://www.cnblogs.com/whongs/p/9147914.html