【iOS】多线程

文章目录

  • 前言
  • 一、多线程的选择方案
  • 二、GCD和NSOperation的比较
  • 二、多线程相关概念
    • 任务
    • 队列
  • 三、死锁情况
    • 主队列加同步任务
  • 四、任务队列组合
    • 主队列+异步
    • 并发队列+异步


前言

这两天将iOS的多线程的使用都看了一遍,iOS的多线程方案有许多,本篇博客主要总结一下不同方案之间的区别以及面试一般会问到的问题

一、多线程的选择方案

技术方案简介语言线程生命周期使用频率
pthread一套通用的多线程API,适用于Unix/Linux/Windows等系统,跨平台/可移植,使用难度大C程序员管理几乎不用
NSThreadNSThread是苹果官方提供的,使用起来更加面向对象,简单易用,可以直接操作线程对象OC程序员管理几乎不用
GCD旨在替代NSThread等线程技术充分利用设备的多核C自动管理经常使用
NSOperation基于GCD的更高一层封装OC自动管理经常使用

二、GCD和NSOperation的比较

关系:
GCD面向底层C语言的API
NSOperation使用GCD进行封装的

对比

  • GCD是苹果官方推荐的多线程方案,使用起来比较方便,更加轻量级
  • GCD只支持FIFO的队列,NSOperation可以设置最大并发数控制串行并行以及通过添加依赖关系来调整执行顺序,这些都是GCD做不到的
  • NSOpration甚至可以跨队列设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier任务才能控制执行顺序,较为复杂
  • NSOperation支持KVO(面向对象)可以检测operation是否正在执行、是否结束、是否取消
- (void)viewDidLoad {[super viewDidLoad];self.operationQueue = [[NSOperationQueue alloc] init];[self.operationQueue addObserver:selfforKeyPath:@"operations"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:NULL];
}

二、多线程相关概念

任务

就是执行的操作,比如GCD中的Block。
执行任务有两种方式:同步执行与异步执行

同步执行(sync):

  • 同步添加任务到指定的队列中,在添加的任务结束之前线程会一直等待,无法执行其他操作
  • 只能在当前线程中执行任务,不具备开启新线程的能力。

异步执行(async):

  • 异步添加任务到指定的队列中,它不会做任何等待,添加后立即返回不会阻塞线程、可以继续执行任务.
  • 可以在新的线程中执行任务,具备开启新线程的能力。

这样子来看可能比较抽象,我们用代码层面来理解就是:

进入dispatch_sync函数后程序不会立刻返回,因此会阻塞线程
而进入dispatch_async函数后程序会立刻返回,不会妨碍进行下一步操作

队列

这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则。GCD 中有两种队列串行队列和并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

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

三、死锁情况

主队列加同步任务

- (void)syncTaskWithMain {dispatch_queue_t mainQueue = dispatch_get_main_queue();dispatch_sync(mainQueue, ^{NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程NSLog(@"任务2");});
}// 在主线程中调用 syncTaskWithMain
- (void)viewDidLoad {[super viewDidLoad];[self syncTaskWithMain];
}

在上述代码中,我们在主线程的viewDidLoad方法中调用了asyncTaskWithMain函数,而在asyncTaskWithMain函数中,我们使用dispatch_sync向主队列提交了一个同步任务。
这种情况会导致死锁,原因如下:

  1. [self syncTaskWithMain]被调用时,主线程进入了asyncTaskWithMain函数。
  2. asyncTaskWithMain函数中,dispatch_sync函数会等待主队列空闲,然后在主队列中同步执行提交的任务。
  3. 但是,由于主线程正在执行syncTaskWithMain函数,所以主队列被占用,无法空闲。
  4. 因此,dispatch_sync函数会一直等待主队列空闲,而主线程也会一直被阻塞在syncTaskWithMain函数中,从而导致死锁。

为了避免死锁,我们应该在syncTaskWithMain函数中使用dispatch_async函数向主队列提交异步任务,或者在其他串行队列中使用dispatch_sync函数提交同步任务。

也就是二者相互等待造成死锁

四、任务队列组合

在这里插入图片描述
也就是只有当异步才会开辟新线程

主队列+异步

这里需要注意的一点是主队列+异步不会开辟新线程,这是由主队列的特性决定的

主队列+异步时既不会创建新的线程,也不会阻塞线程,我们来分析一下原因

主队列(Main Dispatch Queue)
主队列是一个特殊的串行队列,它在应用的主线程上执行任务。由于它是串行的,它一次只能执行一个任务。这意味着如果你在主队列上使用 dispatch_async 来提交一个任务,这个任务会被放到队列的末尾等待执行。

为什么不会创建新的线程
使用 dispatch_async 将任务提交到主队列时,这些任务不会创建新线程,因为:

  • 主队列特性:
    主队列绑定于主线程,所有在主队列上提交的任务都必须在主线程上执行。这是由于主线程通常处理所有的 UI 更新和用户交互,所以系统保证主队列的任务在主线程上顺序执行。
  • 任务调度:
    dispatch_async 函数只是将任务异步地放入队列中,它本身不关心任务的执行在哪个线程进行,任务的执行线程完全取决于队列的性质。由于主队列特性,即使使用 dispatch_async,任务仍然会在主线程上执行

为什么不会导致阻塞
使用 dispatch_async 提交任务到主队列时,不会阻塞主线程,原因包括:

  • 异步执行:
    dispatch_async 是异步执行的,这意味着它会立即返回,不会等待任务执行完成。因此,即使任务最终在主线程上执行,dispatch_async 本身也不会阻塞主线程。
  • 执行时机:
    由于主队列是串行队列,提交到主队列的异步任务会在先前的任务完成后按顺序执行。如果主线程当前正在处理其他任务(如用户输入、动画等),那么主队列上的任务会等待直到主线程空闲。

也就是当主线程的所有的原先的任务都执行完后才回去执行添加到主队列中的异步任务

-(void)asyncTaskWithMain{NSLog(@"currentThread---%@",[NSThread currentThread]);dispatch_queue_t q = dispatch_get_main_queue();dispatch_async(q, ^{NSLog(@"1---%@",[NSThread currentThread]);NSLog(@"任务1");});NSLog(@"4");
}// viewC[self asyncTaskWithMain];NSLog(@"等待");NSLog(@"等待");NSLog(@"等待");NSLog(@"等待");

输出:
在这里插入图片描述

并发队列+异步

同时如果是全局并发队列+异步,那么不会等待主队列任务执行完毕,两个线程会同时执行任务

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_async(globalQueue, ^{NSLog(@"1---%@",[NSThread currentThread]);NSLog(@"任务1");});

输出:
在这里插入图片描述

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

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

相关文章

流畅的python-学习笔记_符合python风格的对象

对象表示形式 查看对象说明,可以通过__repr__和__str__方法,前者主要用于开发者,后者主要用于用户,这两个方法分别对内置函数repr和str函数提供支持 向量类 备选构造方法 classmethod和staticmethod staticmethod用的不是特别…

基于鸢尾花数据集的四种聚类算法(kmeans,层次聚类,DBSCAN,FCM)和学习向量量化对比

基于鸢尾花数据集的四种聚类算法(kmeans,层次聚类,DBSCAN,FCM)和学习向量量化对比 注:下面的代码可能需要做一点参数调整,才得到所有我的运行结果。 kmeans算法: import matplotlib.pyplot a…

音视频开发3 视频基础,图片基础

图片像素(Pixel) 一张图片是由多少个 像素 构成的。 例如一张图片是由60x50组成的。 位深度 bit depth RGB表示法 红(Red)、绿(Green)、蓝(Blue) 除了24bit,常见的位深…

electron 通信总结

默认开启上下文隔离的情况下 渲染进程调用主进程方法: 主进程 在 main.js 中, 使用 ipcMain.handle,添加要处理的主进程方法 const { ipcMain } require("electron"); 在 electron 中创建 preload.ts 文件,从 ele…

在Linux上使用Selenium驱动Chrome浏览器无头模式

大家好,我们平时在做UI自动化测试的时候,经常会用到Chrome浏览器的无头模式(无界面模式),并且将测试代码部署到Linux系统中执行,或者平时我们写个爬虫爬取网站的数据也会使用到,接下来和大家分享…

Elasticsearch初步认识

Elasticsearch初步认识 ES概述基本概念正向索引和倒排索引IK分词器ik_smart最少切分ik_max_word为最细粒度划分 ES索引库基本操作对索引库操作对文档操作 ES概述 Elasticsearch,简称为 ES,是一款非常强大的开源的高扩展的分布式全文检索引擎&#xff0c…

神经网络中的归一化

我们今天介绍一下神经网络中的归一化方法~ 之前学到的机器学习中的归一化是将数据缩放到特定范围内,以消除不同特征之间的量纲和取值范围差异。通过将原始数据缩放到一个特定的范围内,比如[0,1]或者[-1,1],来消除不同特征之间的量纲和取值范围…

【前沿模型解析】一致性模型CM(一)| 离散时间模型到连续时间模型数学推导

文章目录 1 离散时间模型2 连续时间模型 得到 SDE 随机微分方程2.1 从离散模型到SDE的推理步骤 3 补充:泰勒展开近似 1 − β i \sqrt{1-\beta_i} 1−βi​ ​ CM模型非常重要 引出了LCM等一系列重要工作 CM潜在性模型的数学公式推导并不好理解 一步一步&#xf…

Springboot框架web开发实用功能-02

在些模块中汇总了一些web开发常用的配置和功能。 涉及的模块 springboot-common-config, 端口号:17000 Springboot框架web开发常用功能 Restful接口定义 查询参数 Data public class QueryParam {private String key;private String value; }Control…

C#上位机源程序 下位机单片机实现控制电机

基于C#的上位机编程程序&#xff0c;通过上位机控制下位机实现电脑操作控制步进电机的转动 程序 #include<reg52.h>#define uchar unsigned char#define uint unsigned int#include "2401.h"#include "delay.h"#include "ds18b20.h"sbit I…

力扣每日一题110:平衡二叉树

题目 简单 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,3,3,null,null,4,4] 输出&#xff1a;false示例 3&#xff1a; …

python从0开始学习(四)

目录 前言 1、算数运算符 1.1 //:整除运算符 1.2 %:取模操作 1.3 **&#xff1a;幂运算 2、赋值运算符 3、比较运算符 4、逻辑运算符 5、位运算符 5.1 &&#xff1a;按位与 5.2 |&#xff1a;按位或 5.3 ^&#xff1a;按位异或 5.4 ~&#xff1a;按位取反 5.5…

Linux学习笔记(3)---- Debian测试网速指令及查看是否千兆网卡

测试网速指令 在Debian系统中&#xff0c;测网速的指令主要有以下几种方法&#xff1a; 使用speedtest-cli工具&#xff1a; speedtest-cli是一个常用的网络速度测试工具&#xff0c;可以通过命令行进行安装和运行。首先&#xff0c;需要安装speedtest-cli&#xff1a; sud…

工业物联网技术在生产流程中的应用及优势与挑战——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的不断发展&#xff0c;物联网技术逐渐渗透到各个行业中&#xff0c;尤其是在工业领域&#xff0c;工业物联网的应用正在逐步重塑生产流程。本文将探讨工业物联网如何影响生产流程&#xff0c;并分析其带来的优势和挑战。 一、工…

k8s保持pod健康

存活探针 Kubemetes 可以通过存活探针 (liveness probe) 检查容器是否还在运行。可以为 pod 中的每个容器单独指定存活探针。如果探测失败&#xff0c;Kubemetes 将定期执行探针并重新启动容器。 Kubemetes 有以下三种探测容器的机制&#xff1a; HTTP GET 探针对容器的 IP 地…

java学习记录最后一篇

面向对象编程 封装 该露的露&#xff0c;该藏的藏 我们程序设计要追求“高内聚&#xff0c;低耦合”。高内聚就是类的内部数据细节由自己完成&#xff0c;不允许外部干涉&#xff1b;低耦合&#xff1a;仅暴露少量的方法给外部使用。 封装&#xff08;数据的隐藏&#xff0…

AI部署指南

部署指南 建议大家尽可能的自己去部署&#xff0c;如果实在懒得搞&#xff0c;可以找我来帮你部署&#xff0c;详情参考 服务器代部署说明。 由于时间仓促&#xff0c;文档可能尚未详尽&#xff0c;我将在后续逐步补充详细的说明文档。 架构草图 项目依赖 必选依赖 MySQ…

5月3日江苏某厂冷却塔清洗工作汇报-智渍洁

5月3日 施工人员&#xff1a;张能超&#xff0c;张伟&#xff0c;刘平&#xff0c;曾巧 施工事项&#xff1a;空冷器脱脂 今日工作进度&#xff0c;清洗6台遇到的问题&#xff0c;就是那个喷雾器不经用&#xff0c;一会儿又坏了 重庆智渍洁环保科技有限公司专注于工业清洗&…

记录创建项目java version 没有8的问题

问题&#xff1a; 解决方案 java版本选择21&#xff08;21可以兼容jdk8&#xff09; SpringBoot选择3.2.5 进入项目后手动在pom.xml中修改版本

安卓手机原生运行 ARM Ubuntu 24.04 桌面版(一)

本篇文章&#xff0c;聊一聊尝试让安卓手机原生运行 Ubuntu&#xff0c;尤其是运行官方未发布过的 ARM 架构的 Ubuntu 24.04 桌面版本。 写在前面 最近的几篇文章&#xff0c;都包含了比较多的实操内容、需要反复的复现验证&#xff0c;以及大量的调试过程&#xff0c;为了不…