Swift Concurrency:用最简单方式理解苹果官方的异步并发编程
Swift Concurrency 是苹果从 Swift 5.5 开始原生支持的一套异步和并发编程工具,目的是让异步代码写起来更简单、更安全、更高效。它用现代语法和机制,帮助开发者避免传统异步编程的复杂和错误,尤其适合处理网络请求、文件操作、复杂计算等耗时任务。
1. 什么是并发(Concurrency)?
并发指的是多个任务的执行时间有重叠,但不一定同时运行。Swift Concurrency 关注如何用结构化、安全的方式管理这些异步任务,避免混乱和错误。
2. Swift Concurrency 的核心概念和特性
2.1 async / await -- 异步函数和等待
- async:标记函数是异步的,表示函数内部可能会暂停执行,等待耗时操作完成。
- await:调用异步函数时使用,表示“等待”异步操作完成后再继续执行。
这样写异步代码就像写同步代码一样简单,避免了回调地狱。
func fetchData() async throws -> String {
let url = URL(string: "https://api.example.com/data")!
let (data, _) = try await URLSession.shared.data(from: url)
return String(data: data, encoding: .utf8) ?? ""
}
Task {
do {
let result = try await fetchData()
print("获取数据:(result)")
} catch {
print("请求失败:(error)")
}
}
2.2 Task -- 异步任务的执行单元
- Task 是执行异步代码的基本单位。
- 支持创建、取消、设置优先级。
- 任务之间可以形成父子关系,自动管理生命周期。
let task = Task {
await someAsyncFunction()
}
// 取消任务
task.cancel()
2.3 结构化并发 -- 任务的管理和组织
- 任务形成树状结构,父任务会等待所有子任务完成。
- 自动处理任务取消和错误传播,避免任务孤儿和资源泄漏。
func loadMultipleData() async {
await withTaskGroup(of: String.self) { group in
group.addTask { await fetchDataFromServer1() }
group.addTask { await fetchDataFromServer2() }
for await result in group {
print("收到数据:(result)")
}
}
}
2.4 Actor -- 保护共享数据安全
- Actor 是一种特殊的类,保证同一时间只有一个任务访问它的内部状态。
- 解决多线程环境下的数据竞争问题,比传统锁机制更安全且性能更好。
actor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
let counter = Counter()
Task {
await counter.increment()
let current = await counter.getValue()
print("计数器当前值:(current)")
}
3. Swift Concurrency 解决了哪些问题?
- 简化异步代码:用 async/await 替代回调,代码更直观。
- 提高安全性:编译器帮你检查错误处理和取消逻辑,减少遗漏。
- 结构化管理任务:自动管理任务生命周期,避免内存泄漏。
- 避免数据竞争:用 Actor 保护共享状态,避免多线程冲突。
- 提升性能和响应性:合理调度任务,避免主线程阻塞,充分利用多核 CPU。
4. 什么时候用 Swift Concurrency?
- 需要执行网络请求、文件读写、数据库操作等耗时任务。
- 保持界面流畅,避免主线程卡顿。
- 管理多个异步任务,且任务间有依赖关系。
- 需要安全访问和修改共享数据。
- 希望代码简洁、易维护,替代传统 GCD、回调等方式。
5. 详细示例代码和说明
5.1 使用 async/await 进行网络请求
func downloadImage() async throws -> UIImage {
let url = URL(string: "https://example.com/image.png")!
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw URLError(.badServerResponse)
}
return image
}
Task {
do {
let image = try await downloadImage()
print("图片下载成功")
} catch {
print("下载失败:(error)")
}
}
5.2 使用 TaskGroup 并发请求多个接口
func fetchUserIDs() async -> [Int] {
await withTaskGroup(of: Int.self) { group in
let servers = ["primary", "secondary", "backup"]
for server in servers {
group.addTask {
return await fetchUserID(from: server)
}
}
var results = [Int]()
for await userID in group {
results.append(userID)
}
return results
}
}
func fetchUserID(from server: String) async -> Int {
// 模拟网络请求延迟
try? await Task.sleep(nanoseconds: 500_000_000)
return Int.random(in: 1...100)
}
Task {
let userIDs = await fetchUserIDs()
print("用户ID列表:(userIDs)")
}
5.3 使用 Actor 保护共享状态
swift
actor BankAccount {
private var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) -> Bool {
if balance >= amount {
balance -= amount
return true
} else {
return false
}
}
func getBalance() -> Double {
return balance
}
}
let account = BankAccount()
Task {
await account.deposit(amount: 1000)
let success = await account.withdraw(amount: 500)
print("取款成功吗? (success)")
print("余额:(await account.getBalance())")
}
6. Swift Concurrency 的性能和安全性优势
- Swift 5.10 及以后版本,编译器能在编译阶段检测数据竞争,避免运行时错误。
- 通过全局执行器和 Actor 串行执行器,保证任务调度合理,避免主线程阻塞。
- Instruments 工具支持并发代码的可视化分析,帮助定位性能瓶颈和错误。
- 任务只在需要时占用 Actor,避免长时间阻塞,提升并行效率。
7. 总结
Swift Concurrency 是苹果为 Swift 设计的现代异步编程方案,核心是 async/await、Task、结构化并发和 Actor。它让异步代码更简单、清晰、安全,避免了传统回调和锁的复杂性,提升了性能和用户体验。无论是网络请求、文件操作,还是复杂的多任务协作,Swift Concurrency 都是首选工具。
欢迎尝试以上示例,结合实际项目,体会 Swift Concurrency 带来的高效与安全。