一、async 函数的本质:可挂起的函数
✅ 什么是 async 函数?
swift
func asyncWork() async {
// 这是一个异步函数
}
async
函数是可以被挂起的函数。- 挂起 ≠ 阻塞线程,而是让出线程去执行其他任务。
- 挂起只发生在
await
处,称为潜在挂起点。
✅ sync 函数可以当作 async 函数使用,反之不行
swift
protocol SomeProtocol {
func work() async
}
struct SomeStruct: SomeProtocol {
func work() {
// ✅ 合法:sync 实现 async 协议方法
}
}
swift
protocol SomeProtocol {
func work()
}
struct SomeStruct: SomeProtocol {
func work() async {
// ❌ 非法:async 实现 sync 协议方法
}
}
二、await:异步等待,非阻塞线程
✅ 示例:顺序执行异步代码
swift
func asyncWork() async -> Int {
return 42
}
let result = await asyncWork() // 不会阻塞线程
await
是潜在挂起点,只有当调用者和被调用者执行上下文不同时,才会真正挂起。- 挂起时,系统会保存当前状态(称为 continuation),并释放线程。
三、Continuation:挂起点的"快照"
- 包含:返回地址、参数、局部变量等。
- 存储在堆中,允许跨线程恢复。
- 由运行时管理,开发者无需直接操作。
四、Task:异步执行的单位
✅ 创建 Task 进入异步上下文
swift
Task {
await callAsyncFunc()
}
- 每个 async 函数都在某个 Task 中运行。
- Task 是异步函数的"容器",类似线程之于 sync 函数。
- Task 本身不具备并发能力,一个 Task 一次只执行一个函数。
✅ Task 的三种状态
- 🔴 suspended:等待调度或外部事件
- 🟡 running:正在线程上运行
- 🟢 completed:执行完成
五、Job:Task 的"同步片段"
swift
Task {
beforeWork()
await asyncWork()
afterWork()
}
- 每个
await
将 Task 拆分为多个 Job。 - Job 是同步执行的最小单位,不包含
await
。 - Job 按顺序执行,不能并发。
六、Actor:线程安全的并发模型
✅ 示例:Actor 隔离状态
swift
actor SomeActor {
let immutableState = 1
var mutableState = 2
func updateState(_ newValue: Int) {
mutableState = newValue
}
}
let actor = SomeActor()
print(actor.immutableState) // ✅ 无需 await
Task.detached {
await print(actor.mutableState) // ✅ 需 await
// actor.mutableState = 3 // ❌ 编译错误
await actor.updateState(3) // ✅ 合法
}
- Actor 保证同一时间只有一个任务访问其可变状态。
- 不可变状态可同步访问,无需
await
。 - 可变状态必须通过
await
调用 actor 方法访问。
七、Executor:Job 的执行器
- Executor 负责将 Job 调度到线程执行。
- 类型:
- Default concurrent executor:非 actor 隔离任务
- Serial executor:每个 actor 一个,顺序执行
- Main executor:主线程,处理
@MainActor
任务
八、Cooperative Thread Pool(CTP):线程池
- Swift Concurrency 使用固定数量线程(= CPU 核心数),避免线程爆炸。
- 所有 executor(除主线程)都从 CTP 借线程。
- 主线程独立,不参与 CTP。
九、线程与 executor 的映射关系
swift
Task.detached {
// 默认并发 executor,CTP 线程
await someAsyncFunction()
// 仍为默认并发 executor,可能换线程
}
swift
actor SomeActor {
func someMethod() async {
// 当前 actor 的 serial executor
await someAsyncFunction()
// 仍为同一 actor executor,可能换线程
}
}
swift
Task { @MainActor in
// 主线程
await someAsyncFunction()
// 仍在主线程
}
十、完整运行机制图解(文字版)
csharp
CPU 核心
↓
Cooperative Thread Pool(固定线程)
↓
Executor(调度 Job)
↓
Job(同步片段)
↓
Task(异步函数容器)
↓
async/await(挂起点与 continuation)
↓
Actor(隔离状态,防止数据竞争)
十一、总结与个人见解
✅ Swift Concurrency 的优势
- 结构化并发:Task、async/await、actor 构成完整模型。
- 线程安全:Actor 提供编译期保证,避免数据竞争。
- 性能优化:CTP 限制线程数,避免线程爆炸。
- 可读性强:异步代码像同步代码一样线性书写。
⚠️ 学习曲线与挑战
- 概念多,机制复杂,需理解底层模型。
- 调试困难,尤其是线程切换与挂起恢复。
- 与旧代码(GCD、delegate)集成需谨慎。
十二、扩展使用场景与实践建议
✅ 场景 1:网络请求 + 数据解析
swift
func fetchData() async throws -> Data {
let url = URL(string: "https://api.example.com")!
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
✅ 场景 2:并发请求多个接口
swift
async let user = fetchUser()
async let posts = fetchPosts()
let result = await (user, posts)
✅ 场景 3:Actor 管理缓存
swift
actor ImageCache {
private var cache: [String: UIImage] = [:]
func image(for key: String) -> UIImage? {
return cache[key]
}
func save(image: UIImage, for key: String) {
cache[key] = image
}
}