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 多线程的概念
举个例子, 我们的程序运行, 都是按照代码从上往下的执行, 但如果遇到需要下载图片的时候, 它就会卡在这里, 等待图片下载完成才会执行下一步, 这样子就不符合我们的实际体验了, 所以我们会把下载图片放到子线程里去操作, 等到下载完成之后才传回给主线程, 这就是多线程的好处, 既不会影响主线程的运行, 又可以完成下载图片的任务.
提示:
- dispatch_async 异步操作,会并发执⾏,无法确定任务的执⾏顺序
- 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 串⾏队列
- 同步任务, 不需要新建线程, 异步任务, 需要⼀个⼦线程, 线程的创建和回收不需要程序员参与!
- “是最安全的一个选择”串⾏行队列只能创建!
2.2 并行队列
- 同步任务, 不需要创建线程并行队列, 异步任务, 有多少个任务, 就开N个线程执⾏行 无论什么队列和什么任务, 线程的创建和回收不需要程序员参与.
- 线程的创建回收⼯作是由队列负责的 “并发”编程, 为了让程序员从负责的线程控制中解脱出来! 只需要⾯对队列和任务!
2.3 GCD的好处
- 通过GCD, 开发者不⽤再直接跟线程打交道, 只需要向队列中添加代码块即可。
- GCD在后端管理着⼀个线程池, GCD不仅决定着代码块将在哪个线程被执⾏, 它还根据可用的系统资源对这些线程进⾏管理. 从而让开发者从线程管理的工作中解放出来, 通过集中的管理线程, 缓解大量线程被创建的问题。
- 使⽤用GCD, 开发者可以将工作考虑为一个队列, 而不是一堆线程,这种并行的抽象模型更容易掌握和使⽤.
GCD的队列
- GCD公开有5个不同的队列: 运⾏在主线程中的主队列,3个不同优先级的后台队列,以及一个优先级更低的后台队列(⽤于 I/O).
- ⾃定义队列: 串⾏行和并⾏行队列,⾃定义队列⾮常强大,建议在开发中使⽤,在⾃定义队列中被调度的所有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