随着 Swift 5.5 的发布,Swift 引入了全新的结构化并发 (Structured Concurrency) 模型。这套模型基于 async/await,彻底改变了我们编写异步代码的方式,告别了传统闭包回调 (Callback) 带来的“毁灭金字塔 (Pyramid of Doom)”。
为什么需要结构化并发?
在结构化并发之前,如果我们有多个异步任务,通常会写出这样的代码:
func fetchUserData(completion: @escaping (User?, Error?) -> Void) {
URLSession.shared.dataTask(with: userURL) { data, response, error in
guard let data = data else {
completion(nil, error)
return
}
do {
let user = try JSONDecoder().decode(User.self, from: data)
completion(user, nil)
} catch {
completion(nil, error)
}
}.resume()
}
这存在几个显著问题:
- 控制流混乱:极易遗漏
completion调用,导致程序挂起。 - 错误处理繁琐:无法直接使用 Swift 的
throw机制,必须通过Result或双可选值。 - 任务无法自动取消:如果用户退出了页面,底层的网络请求仍然在消耗带宽和电量。
Swift 中的 Async/Await
async/await 让异步代码的编写和同步代码一样自然:
func fetchUserData() async throws -> User {
let (data, _) = try await URLSession.shared.data(from: userURL)
return try JSONDecoder().decode(User.self, from: data)
}
这里 await 明确指出了挂起点 (Suspension Point)。当代码执行到这里时,当前线程会被释放去执行其他任务,直到异步网络请求完成后,再由系统调度恢复执行。
Task 与结构化作用域
结构化并发的核心在于生命周期绑定。子任务的生命周期应当与父任务绑定,这通过 Task 和 TaskGroup 实现。
1. 异步绑定 (Async Let)
当你需要并行执行多个任务,且需要等待它们全部完成时,使用 async let 是最简单的方式:
func fetchDashboardData() async throws -> Dashboard {
async let user = fetchUserData()
async let stats = fetchAppStats()
// 两者并行执行,在此处汇合等待
return try await Dashboard(user: user, stats: stats)
}
2. 任务组 (Task Group)
对于动态数量的任务,我们应当使用 withThrowingTaskGroup:
func fetchAllImages(urls: [URL]) async throws -> [UIImage] {
try await withThrowingTaskGroup(of: UIImage.self) { group in
for url in urls {
group.addTask {
let (data, _) = try await URLSession.shared.data(from: url)
return UIImage(data: data) ?? UIImage()
}
}
var images = [UIImage]()
for try await image in group {
images.append(image)
}
return images
}
}
自动取消机制 (Automatic Cancellation)
结构化并发最大的优势之一是自动取消传播。如果父任务被取消,所有的子任务(包括 TaskGroup 中的任务)都会自动接收到取消信号并停止执行:
group.addTask {
// 定期检查取消状态
try Task.checkCancellation()
let (data, _) = try await URLSession.shared.data(from: url)
return UIImage(data: data) ?? UIImage()
}
总结
Swift 结构化并发不仅让代码更加整洁,也让内存安全和资源管理提升到了编译器级别。作为 iOS 开发者,熟练掌握并全面转向 async/await 能够极大地减少 App 里的异步 Bug,让代码更具可维护性。
交流与评论
评论区基于 GitHub Discussions。您可以登录 GitHub 账户发表您的看法。