• 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任务之间是同步执行的!
    • 并发队列异步执行结果中看到开辟了多个线程,并且执行顺序也不是顺序执行。因为异步开多线程的代名词,并发是开多条线程的代名词
    • 有多个线程,操作进来之后它会将这些队列安排在可用的处理器上,同时保证先进来的任务优先处理。
    • 以先进先出的方式,并发调度队列中的任务执行
    • 如果当前调度的任务是同步执行的,会等待任务执行完成后,再调度后续的任务
    • 如果当前调度的任务是异步执行的,同时底层线程池有可用的线程资源,会再新的线程调度后续任务的执行

     

  • 相关阅读:
    inux修改profile文件出错后所有命令不能用
    windows常用批处理脚本
    Namespace + functions versus static methods on a class 命名空间函数和类的静态方法对比
    vs2008(visual studio)使用cppcheck
    保存文件为UTF8格式(Writing UTF8 files in C++).
    C++ smtp发送邮件类(ssl/tls)转自codeproject。
    CString、TCHAR、WCHAR 字符串等转BSTR的几种方法。
    C/C++中全局变量的那些事儿
    [C++] 哪本书是对程序员最有影响、每个程序员都该阅读的书?读书排行。
    (转)修改VS2008(vc)中工程/解决方案/类的名字
  • 原文地址:https://www.cnblogs.com/whongs/p/9147914.html
Copyright © 2020-2023  润新知