iOS主要知识点梳理回顾-2-多线程

news/2025/2/11 7:07:45/

iOS的多线程主要有三种方式,NSThread、GCD(Grand Central Dispatch)NSOperationQueue

        开始,在iOS2发布的时候,苹果同步推出了NSthread和NSOperation。其中NSthread比较简单,仅提供了创建队列、开始、取消、关闭等简单动作。而NSOperation就更高级一些,他是基于队列的任务管理工具,有任务关系、优先级、并发限制、任务取消等功能,相对于NSthread他封装的更好一些,也重一些。这2种方式基本满足了当时开发者的需求,简单开异步任务就用NSThread,任务之间存在关系就用NSOperation + NSOperationQueue来实现。

        2年后,出于降低能耗及更好的适配苹果的硬件等目的,随着iOS4的发布,苹果推出了GCDGCD的能力基本和NSOperation类似,主要差异是他更轻量、灵活。GCD 提供了一个底层的并发框架,其中包含了线程池和队列调度等机制,用于更有效地管理并发任务。推出GCD的同时,苹果也顺带把NSOperationQueue的内部实现做了优化,应用了GCD的一些(或大部分)研发成果。所以可以根据个人习惯选择多线程工具。

NSThread

- (void)createAndStartThread {NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(runTask) object:nil];[thread start];
}- (void)runTask {NSLog(@"线程开始: %@", [NSThread currentThread]);// 模拟耗时任务[NSThread sleepForTimeInterval:1.0]; // 退出[NSThread exit];//NSLog(@"这行不会执行");
}

NSOperation

最基本就不写了,感觉和调用方法没啥区别

依赖关系
- (void)operationWithDependencies {NSLog(@"create operationWithDependencies on %@", NSThread.currentThread);NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"任务 1 执行 %@", NSThread.currentThread);}];NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"任务 2 执行 %@", NSThread.currentThread);}];// operation1 等待 operation2 完成[operation1 addDependency:operation2];NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperations:@[operation1, operation2] waitUntilFinished:NO];NSLog(@"operationWithDependencies cimmit");
}

打印结果

create operationWithDependencies on <_NSMainThread: 0x60000170c000>{number = 1, name = main}

operationWithDependencies cimmit

任务 2 执行 <NSThread: 0x600001752500>{number = 4, name = (null)}

任务 1 执行 <NSThread: 0x600001763200>{number = 6, name = (null)}

如果我们设置了 waitUntilFinished YES,则相同于同步队列,程序会最后打印“operationWithDependencies cimmit

其他功能
  1. 设置最大并发数
  2. 取消所有队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 设置最多并发 2 个任务
queue.maxConcurrentOperationCount = 2;NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"任务1执行 %@", NSThread.currentThread);
}];NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"任务2执行 %@", NSThread.currentThread);
}];[queue addOperations:@[operation1, operation2] waitUntilFinished:YES];// 取消所有队列
[queue cancelAllOperations];

GCD(Grand Central Dispatch)

并发队列

异步任务在非主线程中执行

    dispatch_queue_t queue = dispatch_queue_create("com.example.myQueue", DISPATCH_QUEUE_CONCURRENT);// 同步任务(阻塞当前线程)dispatch_sync(queue, ^{NSLog(@"同步任务 - %@", [NSThread currentThread]);});// 异步任务(不阻塞当前线程)dispatch_async(queue, ^{NSLog(@"异步任务 - %@", [NSThread currentThread]);});
全局并发

各自线程不一致,无序

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{NSLog(@"全局并发队列任务1 - %@", [NSThread currentThread]);});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{NSLog(@"全局并发队列任务2 - %@", [NSThread currentThread]);});dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{NSLog(@"全局并发队列任务3 - %@", [NSThread currentThread]);});
串行队列

以下代码推荐小白朋友反复执行观察规律。串行队列有个特点,加入队列的任务会严格按着加入顺序执行,无论他是同步还是异步。当同步任务被添加到队列后,程序会等待同步任务前加入的所有任务执行完毕,然后执行同步任务,然后继续往后执行。其中同步任务在主线程执行,异步任务在同一个子线程执行。

    dispatch_queue_t queue = dispatch_queue_create("com.example.barrier", nil);dispatch_async(queue, ^{NSLog(@"异步任务1 %@", NSThread.currentThread);});dispatch_async(queue, ^{NSLog(@"异步任务2 %@", NSThread.currentThread);});dispatch_sync(queue, ^{NSLog(@"同步任务 %@", NSThread.currentThread);});dispatch_async(queue, ^{NSLog(@"异步任务3 %@", NSThread.currentThread);});NSLog(@"主线程任务");

以上代码,4个任务的顺序是绝对不变的,主线程任务一定会在同步任务后执行,可能在3前,可能在3后,这事不确定的。

任务组 dispatch_group
   dispatch_group_t group = dispatch_group_create();// 自动入离队1dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{NSLog(@"任务1");});// 自动入离队2dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{NSLog(@"任务2");});// 手动入队dispatch_group_enter(group);dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@"延时任务完成");// 手动离队dispatch_group_leave(group);});dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"所有任务完成,回到主线程");});
栅栏任务
dispatch_queue_t queue = dispatch_queue_create("com.example.barrier", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{NSLog(@"任务1");
});dispatch_async(queue, ^{NSLog(@"任务2");
});dispatch_barrier_async(queue, ^{NSLog(@"栅栏任务");
});dispatch_async(queue, ^{NSLog(@"任务3");
});
信号量

可以用于控制并发数,实现锁的效果等

- (void)concurrentTaskControl {dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); // 最大并发数为2dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);for (int i = 0; i < 5; i++) {dispatch_async(queue, ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 请求信号量NSLog(@"任务 %d 开始 - %@", i, [NSThread currentThread]);sleep(2);  // 模拟耗时任务NSLog(@"任务 %d 完成", i);dispatch_semaphore_signal(semaphore); // 释放信号量});}
}
其他场景

1、延迟执行dispatch_after,我经常用它解决一些定期权限检查之类的,就可以不用定时器

2、单例dispatch_once_t

3、并行遍历dispatch_apply

一些细节对比

1)任务组:DispatchGroup和NSOperationQueue类似,区别在于DispatchGroup提供的函数notify(queue:execute:)、enter()、leave()等,使得任务和队列之间的关系更灵活,不必强依赖于任务的状态。而OperationQueue中任务的整体管理依赖任务的状态,OperationQueue取消之后,如果任务还未开始执行,将不再执行;如果任务正在执行中,可继续执行,特殊情况需要终断的,可通过Operation的isCancelled属性来判断是否被取消了。

2)GCD的通过信号量来控制某个队列并发数,而OperationQueue用的是maxConcurrentOperationCount属性来控制,用起来差异不大,OperationQueue的代码更少、更直观。

3)GCD没有任务依赖关系的直接设置,但是可以通过栅栏(dispatchBarriers)来实现先后任务等待,NSOperation可以直接设置谁依赖谁,更直接。

4)GCD和NSOperation都能设置任务优先级,但是不要以为高优先级的任务就一定比低优先级的任务先执行,具体的执行时间还受到其他因素的影响,比如操作的依赖关系、操作的并发性设置等。


http://www.ppmy.cn/news/1571096.html

相关文章

XY2-100的Verilog实现

xy2_100.v module xy2_100(input clk,input tx_init, //当产生上升沿时&#xff0c;开始发数据input wire [15:0]x_pos,input wire [15:0]y_pos,input wire [15:0]z_pos,output clk_2MHz_o,//输出2MHz时钟output sync_o,output x_ch_o,output y_ch_o,output z_ch_o,output tx_…

Python Pandas(3):DataFrame

1 介绍 DataFrame 是 Pandas 中的另一个核心数据结构&#xff0c;类似于一个二维的表格或数据库中的数据表。它含有一组有序的列&#xff0c;每列可以是不同的值类型&#xff08;数值、字符串、布尔型值&#xff09;。DataFrame 既有行索引也有列索引&#xff0c;它可以被看做由…

java-初识List

List&#xff1a; List 是一个接口&#xff0c;属于 java.util 包&#xff0c;用于表示有序的元素集合。List 允许存储重复元素&#xff0c;并且可以通过索引访问元素。它是 Java 集合框架&#xff08;Java Collections Framework&#xff09;的一部分 特点&#xff1a; 有序…

协议-WebRTC-HLS

是什么&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09; 实现 Web 浏览器和移动应用程序之间通过互联网直接进行实时通信。允许点对点音频、视频和数据共享&#xff0c;而无需任何插件或其他软件。WebRTC 广泛用于构建视频会议、语音通话、直播、在线游…

【MySQL】:用C语言连接MySQL

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家带来用C语言链接数据库的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数…

基础入门-HTTP数据包红蓝队研判自定义构造请求方法请求头修改状态码判断

知识点&#xff1a; 1、请求头&返回包-方法&头修改&状态码等 2、数据包分析-红队攻击工具&蓝队流量研判 3、数据包构造-Reqable自定义添加修改请求 一、演示案例-请求头&返回包-方法&头修改&状态码等 数据包 客户端请求Request 请求方法 …

嵌入式硬件篇---OpenMV串口流和缓冲区

文章目录 前言流和缓冲区1. 流&#xff08;Stream&#xff09;的含义定义在OpenMV中的体现 2. 缓冲区&#xff08;Buffer&#xff09;的含义定义在OpenMV中的实现 3. 流与缓冲区的协同工作数据发送流程数据接收流程 4. 缓冲区管理的关键方法发送缓冲区管理接收缓冲区管理示例代…

尚硅谷课程【笔记】——大数据之Linux【二】

课程视频链接&#xff1a;尚硅谷大数据Linux课程 五、Linux实用指令 Linux系统运行级别&#xff1a; 0&#xff1a;关机 1&#xff1a;单用户【找回丢失密码】 2&#xff1a;多用户状态没有网络 3&#xff1a;多用户状态有网络 4&#xff1a;保留 5&#xff1a;图形界面 6&…