GCD的使用和原理 | 青训营笔记

94 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第3天

1、任务和队列

  • 步骤
    • 创建任务:需要做什么事情,要执行的操作
    • 将任务存放到队列中,GCD会自动将队列的任务取出,放到对应的线程中去执行,遵循先进先出原则

image.png

2、开启子线程

  • 1、创建一个队列
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
  • 2、创建一个任务
dispatch_block_t task = ...;
  • 3、异步执行
dispatch_async(queue, task);
//第一个参数是队列,第二个参数是任务
  • 用CGD异步加载网络图片
//开启异步加载图片信息
dispatch_async(dispatch_get_global_queue(0,0),^{
    UIImage *image = [UIImage imageWithData:data];
    //回到主线程更新UI
    dispatch_sync(dispatch_get_main_queue(),^{
        self.imageView.image = image;
        [self.imageView sizeToFit];
    },
};

3、队列

  • 队列两大类型
    • 并发队列
      • 可以让多个任务同时执行(自动开启多个线程同时执行任务)
      • 并发功能只有在异步(dispatch_async)函数下才有效
    • 串行队列
      • 让任务一个接一个按顺序执行
    • 主队列
    • 全局队列

(1)串行队列

  • 串行同步执行(在当前线程执行,不开新线程)

创建串行队列 DISPATCH_QUEUE_SERIAL参数表示串行队列

dispatch_queue_t queue = dispatch_queue_create("队列名",DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue,^{
    NSLog("");//在当前线程执行(不一定是主线程)
});
  • 串行异步执行(会开启线程,但是只开启一个线程,有顺序执行)
//创建串行队列DISPATCH_QUEUE_SERIAL
dispatch_queue_t queue = dispatch_queue_create("名字",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue,^{
    NSLog("");(在一个新线程执行)
});

(2)并行队列

  • 并行同步执行(不开线程,在当前线程执行)与串行队列效果一样
//创建并行队列DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("",DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue,^{
    NSLog("");
});
  • 并行异步执行(开启多个线程,任务进行无顺序,程序性能高)
//创建并行队列DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue,^{
    NSLog("");//开启多个线程,无序
});

(3)主队列 (全局串行队列)

  • 特点
    • 先按顺序执行完主线程上的代码,才会执行主队列的任务
  • 主队列,异步执行
dispatch_async(dispatch_get_main_queue(),^{
    NSLog("");//在主线程当中顺序执行
}
  • 主队列,同步执行
    • 在主线程中执行主队列同步执行会造成死锁
    • 主队列上的任务需要等待主线程的代码执行完,但是主线程上的代码是主队列上的任务,造成矛盾,死锁
//只能在在子线程中使用主队列同步执行
dispatch_sync(dispatch_get_main_queue(),^{
    NSLog("");//在主线程当中顺序执行
}
  • 主队列和串行队列的区别
    • 串行队列:必须等待一个任务执行完成,在调度另一个任务
    • 主队列:如果主线程代码还未执行完,主队列将不会调度任务,同时满足串行队列

(4)全局队列

  • 全局队列本质上是并发队列 dispatch_get_global_queue(0,0)
  • 全局队列和并行队列的区别
    • 并行队列有名称,可以跟踪错误,而全局队列没有
    • 在MRC中,并行队列是create,需要手动release,而全局队列不需要
  • dispatch_get_global_queue(0,0)参数
    • 第一个参数:表示优先级,0为默认优先级
    • 代表了线程的调用优先顺序

4、同步任务

  • 当有多个耗时操作的任务需要按顺序执行
    • 开辟一个子线程
    • 在子线程中使用同步执行方法(与串行队列效果相同)

image.png

5、Barrier阻塞

  • 主要用于在大量异步操作完成后,同一对非线程安全对象进行更新
  • 适合于大规模的I/O操作
  • 等待该队列中的其他任务都执行完,才会执行阻塞中的代码
dispatch_barrier_async(dispatch_get_global_queue(0,0),^{
    //队列中最后执行的代码
});

6、调度组

 //创建组
 dispatch_group_t group = dispatch_group_create();
 //队列
 dispatch_queue_t queue = dispatch_get_global_queue(0,0);
 //该组有多个异步任务
 dispatch_group_async(group,queue,^{
     NSLog("1");
 });
  dispatch_group_async(group,queue,^{
     NSLog("2");
 }); 
 dispatch_group_async(group,queue,^{
     NSLog("3");
 });
 
 //当该组的所有异步任务都执行完成后,才执行
 dispatch_group_notify(group,dispatch_get_main_queue(),^{
     NSLog("");
 });

7、总结

image.png