Swift
并发
本文详细介绍了 Swift 中的并发编程,包括 async/await、异步序列、任务与任务组、Actor 模型以及 Sendable 类型。
Swift 内置的并发模型提供了一种结构化的方式来编写异步和并行代码。它通过 async/await 语法、结构化并发(Structured Concurrency)和 Actor 模型,让异步代码更易读、更安全。
定义和调用异步函数
使用 async 关键字定义异步函数。调用异步函数时,使用 await 关键字标记可能的暂停点。
func fetchPhoto(url: URL) async throws -> UIImage {
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw PhotoError.invalidData
}
return image
}
func updateUI() async {
do {
let url = URL(string: "https://example.com/photo.jpg")!
let image = try await fetchPhoto(url: url)
// 更新 UI
} catch {
print("Failed to fetch photo: \(error)")
}
}异步序列 (Asynchronous Sequences)
AsyncSequence 协议允许你像遍历普通序列一样遍历异步产生的值。使用 for await 循环。
import Foundation
let url = URL(string: "https://example.com/large-data.csv")!
for try await line in url.lines {
print(line)
}任务和任务组 (Tasks and Task Groups)
任务 (Tasks)
Task 是并发执行的基本单位。你可以使用 Task 初始化器从同步上下文进入异步上下文。
Task {
await updateUI()
}任务组 (Task Groups)
使用 withTaskGroup 或 withThrowingTaskGroup 创建任务组,可以动态添加子任务并并发执行。
func printPhotoGallery() async {
await withTaskGroup(of: UIImage?.self) { group in
let photoNames = ["gallery1", "gallery2", "gallery3"]
for name in photoNames {
group.addTask {
return await downloadPhoto(named: name)
}
}
for await photo in group {
if let photo = photo {
// 处理每张照片
}
}
}
}Actors
Actor 是一种引用类型,用于保护可变状态,防止数据竞争。Actor 一次只允许一个任务访问其可变状态。
actor TemperatureLogger {
var measurements: [Int] = []
func log(_ measurement: Int) {
measurements.append(measurement)
}
var max: Int {
return measurements.max() ?? 0
}
}
let logger = TemperatureLogger()
Task {
await logger.log(25)
print(await logger.max)
}Sendable 类型
Sendable 协议用于标记可以在并发域之间安全传递的类型。
- 值类型(如结构体、枚举)如果其成员也是
Sendable,则自动符合Sendable。 - Actor 自动符合
Sendable。 - 类 只有在不可变且 final,或者内部实现了同步机制时,才能符合
Sendable。
struct User: Sendable {
var name: String
var age: Int
}Swift 6 引入了严格的并发检查,确保在编译时捕获潜在的数据竞争。
在 GitHub 上编辑
上次更新于