编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 01.UIKit框架学习
  • 02.UIViewController
  • 03.iOS工程面板说明
  • 04.基础控件Swift版
  • 05.手势的处理逻辑
  • 06.通信设计和实践
  • 07.Swift数据的存储
  • 09.Swift版网络请求
  • 10.Swift版数据存储
  • 11.Swift版多媒体实践
  • 12.Swift与ObjC互调
  • 13.Swift多线程开发
  • 14.Swift版SnapKit布局
  • 16.开发SDK实践
  • 17.iOS项目经验积累
  • 18.Swift版grpc请求

13.Swift多线程开发

目录介绍

  • 01.多线程基础概念
    • 1.1 多线程的概念
    • 1.2 Thread的创建
    • 1.3 线程属性和方法
  • 02.多线程GCD说明
    • 2.1 串⾏队列
    • 2.2 并行队列
    • 2.3 GCD的好处
  • 03.DispatchQueue实践
    • 3.1 主线程更新UI
    • 3.2 后台线程做任务
    • 3.3 串行和并发队列
    • 3.4 同步和异步任务
  • 04.OperationQueue实践
    • 4.1 添加操作到队列
    • 4.2 控制并发度
    • 4.3 按指定顺序执行
    • 4.4 取消任务执行
  • 05.其他一些多线程
    • 5.1 DispatchGroup使用
  • 10.参考博客文章

01.多线程基础概念

1.1 多线程的概念

举个例子, 我们的程序运行, 都是按照代码从上往下的执行, 但如果遇到需要下载图片的时候, 它就会卡在这里, 等待图片下载完成才会执行下一步, 这样子就不符合我们的实际体验了, 所以我们会把下载图片放到子线程里去操作, 等到下载完成之后才传回给主线程, 这就是多线程的好处, 既不会影响主线程的运行, 又可以完成下载图片的任务.

提示:

  1. dispatch_async 异步操作,会并发执⾏,无法确定任务的执⾏顺序
  2. dispatch_sync 同步操作,会依次顺序执⾏,能够决定任务的执行顺序

PS: 线程是有限的, 不可以无休止的增加, 而主线程的大小只有1MB, 子线程都是512KB.

1.2 Thread的创建

可以使用 Thread 类来创建和使用线程。以下是使用 Thread 的一般步骤:

1.创建线程:

let myThread = Thread(target: self, selector: #selector(runThread), object: nil)

2.实现线程方法:实现了一个名为 runThread 的方法,用于在线程中执行任务。请注意,方法需要使用 @objc 标记,并且没有参数。

@objc func runThread() {
    // 在线程中执行任务。可以做一些耗时操作
}

3.启动线程:

myThread.start()

然后测试一下案例,如下所示:

let thread1 = Thread(target: self, selector: #selector(threadMethod1), object: nil)
let thread2 = Thread {
    print("thread2 \(Thread.current)")
}
thread1.start()
thread2.start()

//通过类方法开辟的两个子线程,不返回Thread对象,创建后即就绪状态,无需start()方法。
Thread.detachNewThreadSelector(#selector(threadMethod3), toTarget: self, with: nil)
Thread.detachNewThread {
    print("thread4 \(Thread.current)")
}

//打印数据如下
thread1 <NSThread: 0x60000171e540>{number = 11, name = (null)}
thread3 <NSThread: 0x60000176e380>{number = 13, name = (null)}
thread4 <NSThread: 0x60000174f180>{number = 14, name = (null)}
thread2 <NSThread: 0x60000171d440>{number = 12, name = (null)}

02.多线程分类

2.1 串⾏队列

  1. 同步任务, 不需要新建线程, 异步任务, 需要⼀个⼦线程, 线程的创建和回收不需要程序员参与!
  2. “是最安全的一个选择”串⾏行队列只能创建!

2.2 并行队列

  1. 同步任务, 不需要创建线程并行队列, 异步任务, 有多少个任务, 就开N个线程执⾏行 无论什么队列和什么任务, 线程的创建和回收不需要程序员参与.
  2. 线程的创建回收⼯作是由队列负责的 “并发”编程, 为了让程序员从负责的线程控制中解脱出来! 只需要⾯对队列和任务!

2.3 GCD的好处

  1. 通过GCD, 开发者不⽤再直接跟线程打交道, 只需要向队列中添加代码块即可。
  2. GCD在后端管理着⼀个线程池, GCD不仅决定着代码块将在哪个线程被执⾏, 它还根据可用的系统资源对这些线程进⾏管理. 从而让开发者从线程管理的工作中解放出来, 通过集中的管理线程, 缓解大量线程被创建的问题。
  3. 使⽤用GCD, 开发者可以将工作考虑为一个队列, 而不是一堆线程,这种并行的抽象模型更容易掌握和使⽤.

GCD的队列

  1. GCD公开有5个不同的队列: 运⾏在主线程中的主队列,3个不同优先级的后台队列,以及一个优先级更低的后台队列(⽤于 I/O).
  2. ⾃定义队列: 串⾏行和并⾏行队列,⾃定义队列⾮常强大,建议在开发中使⽤,在⾃定义队列中被调度的所有Block最终都将被放⼊到系统的全局队列中和线程池中。

提示: 不建议使⽤用不同优先级的队列, 因为如果设计不当, 可能会出现优先级反转, 即低优先级的操作阻塞⾼优先级的操作.

GCD(Grand Central Dispatch ):https://www.jianshu.com/p/2d57c72016c6

03.DispatchQueue实践

3.1 主线程更新UI

1.在主线程上更新UI:使用DispatchQueue.main.async将UI操作封装在闭包中,以确保在主线程上执行。例如:

DispatchQueue.main.async {
    // 在主线程上执行UI操作
}

3.2 后台线程做任务

2.在后台线程上执行任务:使用DispatchQueue.global执行耗时的任务,以避免阻塞主线程。您可以选择使用不同的QoS(Quality of Service)来指定任务的优先级。例如:

DispatchQueue.global(qos: .background).async {
    // 在后台线程上执行任务
}

3.3 串行和并发队列

3.串行队列和并发队列:使用DispatchQueue来创建串行队列和并发队列,以控制任务的执行方式。例如:

// 创建串行队列
let serialQueue = DispatchQueue(label: "com.example.serialQueue")

// 创建并发队列
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)

3.4 同步和异步任务

4.同步和异步任务: 使用DispatchQueue.sync执行同步任务,该任务会阻塞当前线程,直到任务完成。使用DispatchQueue.async执行异步任务,该任务会在后台线程上执行,不会阻塞当前线程。例如:

// 同步任务
DispatchQueue.main.sync {
    // 执行同步任务
}

// 异步任务
DispatchQueue.global().async {
    // 执行异步任务
}

04.OperationQueue实践

OperationQueue是在iOS中进行多线程编程的另一个强大工具。以下是一些使用OperationQueue的技巧:

4.1 添加操作到队列

1.添加操作到队列:使用addOperation方法将操作添加到OperationQueue中。例如:

OperationQueue.main.addOperation {
   // 执行操作的代码
}

4.2 控制并发度

2.控制并发度:OperationQueue具有maxConcurrentOperationCount属性,用于控制队列中同时执行的操作数量。默认情况下,该值为-1,表示没有限制。您可以根据需要设置并发度。例如:

let operationQueue = OperationQueue.main;
operationQueue.maxConcurrentOperationCount = 2 // 最多同时执行2个操作

4.3 按指定顺序执行

3.添加依赖关系:使用addDependency方法为操作添加依赖关系,以确保操作按照指定的顺序执行。例如:

let operationQueue = OperationQueue.main;
let operation1 = BlockOperation {
    print("操作1的代码")
}

let operation2 = BlockOperation {
    print("操作2的代码")
}
operation2.addDependency(operation1) // 操作2依赖于操作1
operationQueue.addOperations([operation1,operation2], waitUntilFinished: false)

4.4 取消任务执行

4.取消操作:使用cancel方法取消操作的执行。取消操作后,它将不再执行。例如:

let operation = BlockOperation {
    // 操作的代码
}

operation.cancel() // 取消操作

05.其他一些多线程

5.1 DispatchGroup使用

DispatchGroup 是一个用于管理多个异步任务的工具。它可以让你等待一组任务完成后再执行其他操作。

let group = DispatchGroup()

// 将任务添加到 DispatchGroup
group.enter()
someAsyncTask1 {
    // 任务完成后离开 DispatchGroup
    group.leave()
}

group.enter()
someAsyncTask2 {
    // 任务完成后离开 DispatchGroup
    group.leave()
}

// 等待 DispatchGroup 中的任务完成
group.notify(queue: .main) {
    // 所有任务完成后执行的操作
    print("所有任务已完成")
}

首先创建了一个 DispatchGroup 对象 group。然后,我们使用 enter() 方法将任务添加到 DispatchGroup 中。在每个异步任务完成后,我们使用 leave() 方法离开 DispatchGroup。

最后,我们使用 notify(queue:execute:) 方法来等待 DispatchGroup 中的所有任务完成。当所有任务完成后,指定的闭包将在指定的队列(这里是主队列)上执行。

10.参考博客文章

  • Swift版本 1.多线程开发 -- CGD的简单使用:https://www.cnblogs.com/iOSCain/p/4529333.html
  • Swift版本 2.多线程开发 -- NSOperation的简单使用:https://www.cnblogs.com/iOSCain/p/4529332.html
  • Swift版本 3.多线程开发 -- Run Loop:https://www.cnblogs.com/iOSCain/p/4529331.html
贡献者: yangchong211
上一篇
12.Swift与ObjC互调
下一篇
14.Swift版SnapKit布局