【iOS】GCD学习

news2025/1/11 7:58:48

GCD的概念

GCD(Grand Central Dispatch),是有Apple公司开发的一个多核编程的解决方案,用以优化应用程序支持多核处理器,是基于线程模式之上执行并发任务。

GCD的优点

  1. 利用设备多核进行并行运算
  2. GCD自动充分使用设备的CPU内核
  3. GCD自动管理线程的生命周期(线程创建、线程调度、线程销毁)
  4. 使用简单

GCD任务和队列

任务

任务就是执行操作,即可以执行的代码;执行任务有两种方式:同步 和 异步。

  • 同步执行: 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。不具备开启新线程的能力。
  • 异步执行:异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。可以在新的线程中执行任务,具备开启新线程的能力。

队列

Dispatch Queue指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,遵循 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务;在 GCD 中有两种队列:串行队列 和 并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

  • 串行队列:每次只有一个任务被执行。让任务一个接着一个地执行。
  • 并发队列:可以让多个任务同时执行。(可以开启多个线程,并且同时执行任务)。

CGD使用步骤

  1. 创建队列
  2. 将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)。

创建队列的方法

  1. 可以使用 dispatch_queue_create 方法来创建队列。该方法需要传入两个参数:
  • 第一个参数表示队列的唯一标识符,用于 DEBUG,可为空。队列的名称推荐使用应用程序 ID 这种逆序全程域名。
  • 第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 表示串行队列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。
// 串行队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
  1. 对于串行队列,GCD 默认提供了:『主队列(Main Dispatch Queue)』。
  • 所有放在主队列中的任务,都会放到主线程中执行。
  • 可使用 dispatch_get_main_queue() 方法获得主队列。
// 主队列的获取方法
dispatch_queue_t queue = dispatch_get_main_queue();

创建任务的方法

GCD 提供了同步执行任务的创建方法 dispatch_sync 和异步执行任务创建方法 dispatch_async。

同步任务: dispatch_sync:

 // 同步执行任务创建方法
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%s",__func__);
    });

异步任务: dispatch_async

  // 异步执行任务创建方法
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%s",__func__);
 
    });

任务和队列不同组合方式的区别:

区别并发队列串行队列主队列
同步(sync)没有开启新线程,串行执行任务没有开启新线程,串行执行任务死锁卡住不执行
异步(async有开启新线程,并发执行任务有开启新线程(1条),串行执行任务没有开启新线程,串行执行任务

注意:从上边可看出: 『主线程』 中调用 『主队列』+『同步执行』 会导致死锁问题。
这是因为 主队列中追加的同步任务 和 主线程本身的任务 两者之间相互等待,阻塞了 『主队列』,最终造成了主队列所在的线程(主线程)死锁问题。
而如果我们在 『其他线程』 调用 『主队列』+『同步执行』,则不会阻塞 『主队列』,自然也不会造成死锁问题。最终的结果是:不会开启新线程,串行执行任务。

CGD的组合使用

串行队列 + 同步执行

不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。

  /**
     * 串行队列 + 同步执行
     * 特点:不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。
     */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
            // 追加任务 1
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
            // 追加任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
            // 追加任务 3
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"syncSerial---end");

运行结果:
在这里插入图片描述

串行队列 + 异步执行

会开启新线程。执行完一个任务,再执行下一个任务。

 /**
     * 串行队列 + 异步执行
     * 特点:会开启新线程。执行完一个任务,再执行下一个任务。
     */
    dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
            // 任务 1
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 3
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"asyncSerial---end");

运行结果:
在这里插入图片描述

并发队列 + 同步执行

不会开启新线程,在当前线程执行任务。执行完一个任务,再执行下一个任务。

  /**
    * 并发队列 + 同步执行
    * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
    */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
           // 任务 1
           [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
           NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
           // 任务 2
           [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
           NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_sync(queue, ^{
           // 任务 3
           [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
           NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"syncConcurrent---end");

运行结果:
在这里插入图片描述

并发队列 + 异步执行

可以开启多个线程,任务同时执行。

   /**
     * 并发队列 + 异步执行
     * 特点:可以开启多个线程,任务同时执行。
     */
    dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
            // 任务 1
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 2
            [NSThread sleepForTimeInterval:3];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    dispatch_async(queue, ^{
            // 任务 3
            [NSThread sleepForTimeInterval:1];              // 模拟耗时操作
            NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    NSLog(@"asyncConcurrent---end");

运行结果:
在这里插入图片描述

同步执行 + 主队列

在主线程中调用 『同步执行 + 主队列』

互相等待卡住不可行

/**
 * 同步执行 + 主队列
 * 特点(主线程调用):互等卡主不执行。
 * 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncMain {
    
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"syncMain---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_sync(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_sync(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    NSLog(@"syncMain---end");
}

在其他线程中调用『同步执行 + 主队列』

不会开启新线程,执行完一个任务,再执行下一个任务

// 使用 NSThread 的 detachNewThreadSelector 方法会创建线程,并自动启动线程执行 selector 任务
[NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];

异步执行 + 主队列

只在主线程中执行任务,执行完一个任务,再执行下一个任务。

/**
 * 异步执行 + 主队列
 * 特点:只在主线程中执行任务,执行完一个任务,再执行下一个任务
 */
- (void)asyncMain {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"asyncMain---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        // 追加任务 1
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 2
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    dispatch_async(queue, ^{
        // 追加任务 3
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"3---%@",[NSThread currentThread]);      // 打印当前线程
    });
    
    NSLog(@"asyncMain---end");
}

结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482557.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言-学习之路-03

C语言-学习之路-03 程序流程结构选择结构if语句if...else...语句三目运算符switch语句 循环结构while语句do...while语句for语句嵌套循环 跳转语句break、continue、gotobreak语句continue语句goto语句 程序流程结构 C语言支持最基本的三种程序流程结构:顺序结构、…

三、SpringMVC

三、SpringMVC 1、SpringMVC简介 1.1、什么是MVC MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分 M:Model,模型层,指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 一类称为实体…

REST API 详解

REST API REST(Representational State Transfer,表述性状态转移)是一种用于构建分布式系统的架构风格。REST API(Application Programming Interface,应用程序接口)是一种基于REST风格的网络API&#xff…

Filter 过滤器

Filter过滤器介绍 这里我们讲解Filter的执行流程,从下图可以大致了解到,当客户端发送请求的时候,会经过过滤器,然后才能到我们的servlet,当我们的servlet处理完请求之后,我们的response还是先经过过滤器才…

Packet Tracer - 配置交换机端口安全

Packet Tracer - 配置交换机端口安全 地址分配表 设备 接口 IP 地址 子网掩码 S1 VLAN 1 10.10.10.2 255.255.255.0 PC1 NIC 10.10.10.10 255.255.255.0 PC2 NIC 10.10.10.11 255.255.255.0 非法笔记本电脑 NIC 10.10.10.12 255.255.255.0 目标 第 1 部…

MySQL监控告警及可视化:Zabbix+Percona PMP实现(Part I)

MySQL监控告警及可视化:ZabbixPercona PMP实现(Part I) 准备工作Zabbix Server安装Zabbix Server配置conf文件配置系统服务配置Web服务配置 Zabbix Agent安装Zabbix Agent配置conf文件配置系统服务配置 准备工作 🐬软件下载&#…

ChatGPT提示词工程(五):Transforming转换

目录 一、说明二、安装环境三、转换(Transforming)1. 翻译 Translation2. 语气转换 Tone Transformation3. 格式转换 Format Conversion4. 拼写或语法检查 Spellcheck/Grammar check 一、说明 这是吴恩达 《ChatGPT Prompt Engineering for Developers》…

kubernetes安全框架RBAC

目录 一、Kubernetes 安全概述 二、鉴权、授权和准入控制 2.1 鉴权(Authentication) 2.2 授权(Authorization) 2.3 准入控制 三、基于角色的权限访问控制: RBAC 四、案例:为指定用户授权访问不同命名空间权限 一、Kubernetes 安全概述 K8S安全控…

YOLOv5 txt标签转图像标签(多个标签)

Python YOLOv5 txt标签转图像标签(多个标签 txt的数据如图所示1.读原始图像以及对应的txt文件2.获得原始图像的大小3.生成一张大小相同,黑色背景的图片4.读取txt文件,循环的增加标签5.获得不规则图形(标签)6.完整代码7…

Linux运维:makefile

一.makefile 1.makefile介绍 Makefile 是一种用于自动化构建的文件,它描述了一个软件项目的编译规则和依赖关系,并提供了一些工具来自动执行这些规则。 Makefile 的主要作用如下: 自动化编译:通过 Makefile,可以定…

使用 nvcc 的时候出现“helper_cuda.h”: No such file or directory错误该怎么办(其他xxx.h也是同样的解决方法)

今天在命令行中使用nvcc的时候,出现了“helper_cuda.h”: No such file or directory错误。这个错误信息表示:在编译的时候,找不到helper_cuda.h头文件(其他xxx.h如果也找不到,那么下面的解释和解决方法也通用&#xf…

Java流式操作——Collectors工具类

文章目录 方法实践说明一、前提条件Person类Data类 二、操作maxBy:获取流中最大元素;minBy:获取流中最小元素joining:合并,将流中的元素,以字符串的形式拼接起来summingInt:把流中的元素映射成int类型的元素&#xff0…

springboot第14集:MyBatis-CRUD讲解

注意点:增、删、改操作需要提交事务! 为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上! 编写Mapper接口类 import com.da.pojo.User; import java.util.List; public interface UserMapper…

4.1 指令系统的发展与性能要求

学习目标: 指令系统的发展与性能要求的学习目标: 理解指令系统的发展历程,包括CISC、RISC、VLIW等架构的特点、优缺点以及应用领域;掌握指令系统的性能要求,包括指令集的多样性、可编程性、并行性、效率、可靠性等&a…

ChatGPT学习-如何向ChatGPT提问

​ 最近在学习chatGPT,怎么样的提问是一个好的提问。通过网上找资料肯定不是最好的方法,我想起一句话,“不识庐山真面目,只缘身在此山中”。最好的老师就是chatGPT! 下面先展示下提问成果,我通过xmind生成了思维导图 一…

为什么越来越多的企业选择云计算

目录 一、前言 二、云计算的基础概念 2.1 云计算的定义 2.2 云计算的发展历程 2.3 云计算的基本架构 三、 企业采用云计算的优势 四、 行业应用案例 五、未来发展与挑战 六、总结 随着数字化转型的加速,越来越多的企业开始选择云计算作为信息技术应用的基础…

Linux 用户管理与文件权限

Linux 是一个多用户系统,它允许多个用户同时登陆主机,并为他们分配不同的资源和工作环境进行使用。当然,不同的用户都有文件的私有需求,所以设置不同用户文件的权限管理十分重要。 01 用户与用户组 Linux 中一般将文件访问权限的…

【matplotlib】可视化解决方案——如何正确设置图例

概述 matplotlib 中的图例(Legend)可以帮助我们展示每个数据对应的名称,让图像阅读者更好的认识到图像的数据结构以及绘图者想表达的意思。matplotlib 可以为每一个可见绘图对象(Artist)添加图例,官方建议…

windows10系统如何实现telnet内网穿透

在windows10系统环境中,我们常用的内网穿透方案是远程桌面内网穿透技术方案,存在的弊端是它属于视窗类操作工具。网上很多教人开启windows10的telnet服务的帖子,凡是通过系统设置进入启用或关闭windows应用后勾选telnet客户端这种方式&#x…

ChatGPT实现服务器体验沙箱

服务器体验沙箱 IT 人员在学习一门新技术时,第一个入门门槛通常都是"如何在本地安装并成功运行"。因此,很多技术的官网都会通过沙箱技术,提供在线试用的 playground 或者按步模拟的 tour。让爱好者先在线尝试效果是否满足预期&…