1️⃣ 核心结论
AsyncStream 通过内部维护一个线程安全的队列和 continuation(挂起点)机制,实现 producer/consumer 模型。生产者可以在任意线程产生元素,消费者通过
for await异步迭代获取元素,Swift runtime 自动保证线程安全和 Task 挂起/恢复。
一句话:内部队列 + continuation + executor 串行化 = 安全的异步流。
2️⃣ AsyncStream 构成要素
-
Producer
- 调用
yield(_:)产生元素 - 可以在任意线程执行
- 调用
-
Consumer
for await element in stream迭代元素- 消费者 Task 会在元素尚不可用时挂起
-
Continuation
- runtime 保存 Task 的挂起状态
- 数据到达后 resume Task
-
内部队列
- 缓存还未被消费的元素
- 保证生产者和消费者不同线程也能安全交互
3️⃣ Producer/Consumer 流程
let stream = AsyncStream<Int> { continuation in
// Producer
Task.detached {
for i in 0..<3 {
continuation.yield(i) // 产生元素
try await Task.sleep(nanoseconds: 500_000_000)
}
continuation.finish() // 流结束
}
}
// Consumer
Task {
for await element in stream {
print(element) // 消费元素
}
}
流程解释
-
Producer 调用 yield
- 将元素放入内部线程安全队列
- 若有挂起的消费者 Task → 调用 continuation.resume() 恢复 Task
-
Consumer 调用 next()/for await
- 如果队列为空 → Task 挂起,状态保存在 continuation
- 队列有数据 → 立即返回元素
- Task resume 后继续循环
-
线程安全
- yield 和 next() 可以在不同线程调用
- 内部队列 + continuation + Swift runtime 保证同步访问
- 无需显式锁
4️⃣ 内部原理
Producer Thread
└─ yield(x)
├─ 入队 (Thread-safe)
└─ 如果有挂起消费者 → resume Task
Consumer Task
└─ await next()
├─ 队列有元素 → 返回
└─ 队列空 → Task suspend → 保存 continuation
元素生成 → resume 挂起 Task → Task 获取元素
- 队列:缓存未消费数据
- continuation:挂起点,保存 Task 状态
- resume:恢复挂起 Task
- 串行化:每个元素消费顺序一致,线程安全
5️⃣ AsyncThrowingStream 也是类似机制
- 区别在于 finish 可以带 error
- Consumer 使用
for try await - 错误通过 continuation 恢复挂起 Task 并抛出
6️⃣ 优势总结
-
天然 producer/consumer
- 生产者异步生成数据
- 消费者异步迭代
-
线程安全
- 内部队列 + continuation + runtime 串行化
- yield/next 可跨线程调用
-
异步挂起/恢复
- 避免阻塞线程
- 支持结构化并发
-
可组合
- 可以与 TaskGroup / async let 配合,构建复杂异步流水线
7️⃣ 面试必背总结
AsyncStream 通过内部线程安全队列 + continuation 实现 producer/consumer 模型。生产者可以在任意线程调用
yield产生元素,消费者通过for await异步迭代获取元素;如果队列为空,消费者 Task 挂起,元素到达后由 runtime resume Task,从而保证线程安全和异步流顺序一致性。