GCD

作者: Gunks | 来源:发表于2020-03-29 22:25 被阅读0次

    https://www.jianshu.com/p/77c5051aede2

    \color{red}{注释}: GCD的两个核心概念:任务和队列

    • 任务:执行什么操作
    • 队列:用来存放任务,分为:并行队列和串行队列
      并行队列:
             可以让多个任务并发执行,以提高执行效率
             并发功能仅在异步(dispatch_async)函数下才有效
      串行队列:
             在当前线程中让任务一个接着一个地执行
    

    1.创建队列

    // 队列类型
    dispatch_queue_t
    // 第一个参数:队列名称  第二个参数:队列类型
    dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
      // 队列类型
      // 串行队列标识:本质就是NULL,但建议不要写成NULL,可读性不好
      DISPATCH_QUEUE_SERIAL
      // 并行队列标识
      DISPATCH_QUEUE_CONCURRENT
    
    1.1 创建并行队列的两种方式
    • 第一种
      dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
      
    • 第二种
      // 第一个参数:队列优先级
      // 第二个参数:保留参数,暂时无用,用0即可
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      // 全局并发队列的优先级
      #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 // 后台
      
    1.2 创建串行队列的两种方式
    • 第一种
      // 创建串行队列(队列类型传递DISPATCH_QUEUE_SERIAL或者NULL)
      dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    
    • 第二种
      // 主队列中的任务,都会放到主线程中执行
      dispatch_queue_t queue = dispatch_get_main_queue();
    

    —————————————————————————————————————————————

    2.同步(sync)函数 \color{red}{和} 异步(async)函数

    • 函数作用:将任务添加到队列中
    • 函数类型:决定是否有开启新线程的能力

    2.1 同步函数:不具备开启新线程的能力,只能在当前线程中执行任务
    // queue:队列
    // block:任务
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
    
    2.2异步函数:具备开启线程的能力,但不一定开启新线程,比如:当前队列为主队列,异步函数也不会开启新的线程
    // queue:队列
    // block:任务
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
    

    \color{red}{\Large{经验总结}}

    • 通过异步函数添加任务到队列中,任务不会立即执行
    • 通过同步函数添加任务到队列中,任务会立即执行

    —————————————————————————————————————————————

    3.程序猿只需要做下列事情

    • 3.1 创建队列(是否具备开起新线程能力)
    • 3.2 指定队列类型(同步异步)
    base.png

    —————————————————————————————————————————————

    4.实战

    • 4.1 并行队列+异步函数 (开启多条子线程,任务并行执行
    - (void)asyncConcurrent{
        // 1.创建并行队列
    //    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 2.通过异步函数将将任务加入队列
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"1-----%@", [NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"2-----%@", [NSThread currentThread]);
            }
        });
        dispatch_async(queue, ^{
            for (NSInteger i = 0; i<10; i++) {
                NSLog(@"3-----%@", [NSThread currentThread]);
            }
        });
        // 证明:异步函数添加任务到队列中,任务【不会】立即执行
        NSLog(@"asyncConcurrent--------end");
    
        // 释放队列,ARC中无需也不允许调用这个方法
    //    dispatch_release(queue);
    }
    
    • 4.2 串行队列+异步函数 (开启一条子线程,任务是有序的在子线程上执行)
    - (void)asyncSerial{
        // 1.创建串行队列
        dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    //    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", NULL);
        // 2.通过异步函数将任务加入队列
        dispatch_async(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
        // 证明:异步函数添加任务到队列中,任务【不会】立马执行
        NSLog(@"asyncConcurrent--------end");
    }
    
    • 4.3 主队列+异步函数 (不开启子线程,任务是在主线程中有序执行)
    - (void)asyncMain{
        // 1.获得主队列
        dispatch_queue_t queue = dispatch_get_main_queue();
        // 2.通过异步函数将任务加入队列
        dispatch_async(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
    }
    
    • 4.4 并行队列+同步函数(不会开启子线程,任务是有序执行)
    - (void)syncConcurrent{
        // 1.获得全局的并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 2.通过同步函数将任务加入队列
        dispatch_sync(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
        // 证明:同步函数添加任务到队列中,任务【立马执行】
        NSLog(@"syncConcurrent--------end");
    }
    
    • 4.5 串行队列+同步函数(不会开启线程,任务是有序执行)

    \color{red}{注:易发生死锁}

    • 下面的用法会发生死锁吗?
    - (void)syncMain{
        // 1.创建串行队列
        dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
        // 2.将任务加入队列
        dispatch_sync(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
    }
    
    • 答案:上面的用法不会发生死锁,原因分析如下
      • 虽然都是在主线程上执行的,但任务在不同的队列中所以不会发生阻塞
      • \color{red}{\Large{syncMain}}函数是在主队列中
      • 其他的任务是在新建的串行队列中
    • 4.5.2 \color{red}{\Large{死锁的几中场景}}
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
           NSLog(@"1-----%@", [NSThread currentThread]);
           // 这里阻塞了
           dispatch_sync(queue, ^{
                 NSLog(@"2-----%@", [NSThread currentThread]);
           });
    });
    
      - (void)syncMain  {
          // 获得主队列
          dispatch_queue_t queue = dispatch_get_main_queue();
          // 这里阻塞了
          dispatch_sync(queue, ^{
              NSLog(@"1-----%@", [NSThread currentThread]);
          });
          dispatch_sync(queue, ^{
              NSLog(@"2-----%@", [NSThread currentThread]);
          });
          dispatch_sync(queue, ^{
              NSLog(@"3-----%@", [NSThread currentThread]);
          });
      }
    
    • 同步函数在任务执行过程中往任务所在的串行队列中添加任务就会导致任务间互相等待,造成死锁
    • 别忘了同步函数添加任务到队列中,任务会立即执行,如果是异步函数就不会发生死锁

    —————————————————————————————————————————————

    5.GCD实现线程间通信

    相关文章

      网友评论

          本文标题:GCD

          本文链接:https://www.haomeiwen.com/subject/tiepuhtx.html