使用GCD

作者: 下页天 | 来源:发表于2018-10-23 17:37 被阅读5次

介绍

  • 什么是 GCD

    全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”,纯C语言,提供了非常多强大的函数

  • GCD的优势

    GCD是苹果公司为多核的并行运算提出的解决方案

    GCD会自动利用更多的CPU内核(比如双核、四核)

    GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

    程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

  • 提示

    GCD存在于libdispatch.dylib这个库中,这个调度库包含了GCD的所有的东西,但任何IOS程序,默认就加载了这个库,在程序运行的过程中会动态的加载这个库,不需要我们手动导入。

    GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法。

    GCD中的函数大多数都以dispatch开头。

任务和队列

  • GCD中有2个核心概念
    • 任务:执行什么操作
    • 队列:用来存放任务
  • GCD的使用就2个步骤
    • 定制任务
    • 确定想做的事情

将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行

提示:任务的取出遵循队列的FIFO原则:先进先出,后进后出

执行任务

  • GCD中有2个用来执行任务的函数

    说明:把右边的参数(任务)提交给左边的参数(队列)进行执行。

    • 用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); queue:队列 block:任务
    • 用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
  • 同步和异步的区别

    • 同步:在当前线程中执行
    • 异步:在另一条线程中执行

队列

  • 队列的类型

    • 并发队列(Concurrent Dispatch Queue)

      可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效
      - 串行队列(Serial Dispatch Queue)

      让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

  • 补充说明

有4个术语比较容易混淆:同步、异步、并发、串行

同步和异步决定了要不要开启新的线程

同步:在当前线程中执行任务,不具备开启新线程的能力

异步:在新的线程中执行任务,具备开启新线程的能力

并发和串行决定了任务的执行方式

并发:多个任务并发(同时)执行

串行:一个任务执行完毕后,再执行下一个任务

  • 串行队列 GCD中获得串行有2种途径

    • 使用dispatch_queue_create函数创建串行队列

      dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); // 队列名称, 队列属性,一般用NULL即可

      示例:dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 创建

    • 使用主队列(跟主线程相关联的队列)

      主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行,使用dispatch_get_main_queue()获得主队列

      dispatch_queue_t queue = dispatch_get_main_queue();

  • 并发队列. GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建,使用dispatch_get_global_queue函数获得全局的并发队列

    dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此参数暂时无用,用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) // 低

  • 各种队列的执行效果


    4.png

block 的定义

block 的定义有点象函数指针,差别是用 ^ 替代了函数指针的 * 号,如下所示:

  • 无参数无返回值
//无参数,无返回值,声明和定义

void(^MyBlockOne)(void) = ^(void){

NSLog(@"无参数,无返回值");  

};  
MyBlockOne();//block的调用;
  • 有参数无返回值
//有参数,无返回值,声明和定义

void(^MyblockTwo)(int a) = ^(int a){

NSLog(@"@ = %d我就是block,有参数,无返回值",a);

  };  
MyblockTwo(100);
  • 有参数有返回值
//有参数,有返回值

int(^MyBlockThree)(int,int) = ^(int a,int b){    

  NSLog(@"%d我就是block,有参数,有返回值",a + b);returna + b; 

 };  
MyBlockThree(12,56);
  • 无参数有返回值(很少用到)
//无参数,有返回值

int(^MyblockFour)(void) = ^{NSLog(@"无参数,有返回值");
        return45;
  };
MyblockFour();
  • 实际开发中常用typedef 定义Block
typedef int (^MyBlock)(int , int);

@property (nonatomic,copy) MyBlock myBlockOne;
self.myBlockOne = ^int (int ,int){
    //TODO
}

系统提供的 dispatch 方法

为了方便地使用 GCD,苹果提供了一些方法方便我们将 block 放在主线程 或 后台线程执行,或者延后执行。

//  后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
     // something
});

// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
     // something
});

// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // code to be executed once
});

// 延迟 2 秒执行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // code to be executed on the main queue after delay
});

GCD 还有一些高级用法,例如让后台 2 个线程并行执行,然后等 2 个线程都结束后,再汇总执行结果。这个可以用 dispatch_group, dispatch_group_async 和 dispatch_group_notify 来实现. 线程分组

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
     // 汇总结果
});

后台运行

使用 block 的另一个用处是可以让程序在后台较长久的运行。在以前,当 app 被按 home 键退出后,app 仅有最多 5 秒钟的时候做一些保存或清理资源的工作。但是应用可以调用 UIApplication 的beginBackgroundTaskWithExpirationHandler方法,让 app 最多有 10 分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。

让程序在后台长久运行的示例代码如下:

// AppDelegate.h 文件
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// AppDelegate.m 文件
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self beingBackgroundUpdateTask];
    // 在这里加上你需要长久运行的代码
    [self endBackgroundUpdateTask];
}
- (void)beingBackgroundUpdateTask
{
    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundUpdateTask];
    }];
}
- (void)endBackgroundUpdateTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
    self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

相关文章

  • iOS-多线程:GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(6种不同组合区别) GCD 线程间的通信...

  • iOS多线程--彻底学会多线程之『GCD』

    GCD 文章目录 GCD简介 任务和队列 GCD的使用步骤 队列的创建方法 任务的创建方法 GCD的基本使用 并行...

  • iOS GCD

    GCD 简介 GCD 任务和队列 GCD 的使用步骤 GCD 的基本使用(六种组合不同区别,队列嵌套情况区别,相互...

  • 多线程之GCD

    GCD介绍 1、GCD简介 2、GCD任务和队列 3、GCD 的基本使用 4、GCD 线程间的通信 5、GCD 的...

  • iOS 关于GCD很详细的描述

    那为什么我们要使用 GCD 呢? 因为使用 GCD 有很多好处啊,具体如下:GCD 可用于多核的并行运算;GCD ...

  • GCD多线程详解

    1. GCD 简介 2. GCD 任务和队列 3. GCD 的使用步骤 4. GCD 的基本使用(6种不同组合区别...

  • iOS多线程--GCD篇

    GCD 文章目录GCD简介任务和队列GCD的使用步骤队列的创建方法任务的创建方法GCD的基本使用并行队列 + 同步...

  • iOS实录16:GCD使用小结(二)

    iOS实录16:GCD使用小结(二) iOS实录16:GCD使用小结(二)

  • iOS GCD的使用

    什么是GCD了解GCD前,需要了解的基础知识GCD的使用使用注意事项 -GCD学习前铺垫-什么是GCDGCD (G...

  • iOS - GCD

    目录 GCD简介 GCD核心概念 GCD队列的使用 GCD的常见面试题 GCD简介 Grand Central D...

网友评论

    本文标题:使用GCD

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