Swift 中的并发与多线程简介
现代 iOS 和 macOS 应用程序越来越需要同时执行多个任务。无论是从网络加载数据、处理图像还是进行复杂的数学计算,都离不开对线程的有效管理。在 Swift 中,并发与多线程的实现达到了最高水平,为开发者提供了强大且安全的工具。
在本文中,我们将介绍三种主要方法:Grand Central Dispatch (GCD)、OperationQueue 以及 Swift 5.5 中引入的现代关键字 async/await。您将学习如何正确选择它们,并避免典型错误,例如竞态条件 (race condition) 和死锁 (deadlock)。
Grand Central Dispatch (GCD) — Swift 中的经典多线程
Grand Central Dispatch (GCD) 是 Apple 的一个底层库,用于管理线程池。开发者无需手动创建和销毁线程——GCD 会自动完成这些工作,将任务分配到可用的 CPU 核心上。
GCD 的主要队列
GCD 有两种类型的队列:串行队列 (serial) 和并发队列 (concurrent)。串行队列中的任务一个接一个地执行,而并发队列中的任务可以同时启动。
// 创建串行队列let serialQueue = DispatchQueue(label: "com.example.serial")serialQueue.async { print("任务 1")}serialQueue.async { print("任务 2")}
// 创建并发队列let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)concurrentQueue.async { print("并发任务 A")}concurrentQueue.async { print("并发任务 B")}全局队列与 QoS
GCD 提供了现成的具有不同优先级 (Quality of Service) 的全局队列。当不需要创建自己的队列时,可以使用它们:
.userInteractive— 用于 UI 更新(最高优先级).userInitiated— 用于用户发起的任务.utility— 用于长时间的后台操作.background— 用于对时间不敏感的任务
DispatchQueue.global(qos: .userInitiated).async { // 繁重的工作 let result = performComplexCalculation() DispatchQueue.main.async { // 返回主线程更新 UI self.updateUI(with: result) }}重要提示: 始终只在主线程 (DispatchQueue.main) 上更新 UI。忽略此规则会导致应用程序出现不可预测的崩溃。
OperationQueue — 任务依赖管理
如果说 GCD 是“瑞士军刀”,那么 OperationQueue 就是一个功能完备的调度器,支持取消、优先级设置以及创建操作之间的依赖关系。每个操作都是 Operation 类(或其子类 BlockOperation)的一个实例。
创建和执行操作
let operationQueue = OperationQueue()operationQueue.maxConcurrentOperationCount = 2 // 限制并发操作数量
let operation1 = BlockOperation { print("操作 1")}let operation2 = BlockOperation { print("操作 2")}
// 添加依赖:operation2 只有在 operation1 完成后才会开始operation2.addDependency(operation1)
operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)取消与优先级
与 GCD 不同,OperationQueue 允许取消特定操作或整个队列:
// 取消一个操作operation1.cancel()
// 取消整个队列operationQueue.cancelAllOperations()
// 设置优先级operation1.