4-1.【协议导向编程】什么是协议导向编程(POP),它解决了传统面向对象设计中的哪些问题?
2026年1月29日 11:05
1️⃣ 什么是协议导向编程(POP) 协议导向编程 是 Swift 提出的编程范式,它的核心思想是: 通过协议(protocol)定义接口和行为,而不是依赖类继承。 通过协议扩展(protocol e
TaskGroup的设计目的,是在保持结构化并发的前提下,
安全地表达“一组并发执行、统一收敛结果的子任务”。
或者更狠一点的说法:
TaskGroup = “不会失控的 fork–join 并发”。
先看一个“天真实现”的问题:
var results: [Int] = []
Task {
Task { results.append(await f1()) }
Task { results.append(await f2()) }
Task { results.append(await f3()) }
}
❌ 问题一堆:
results 有数据竞争let sum = await withTaskGroup(of: Int.self) { group in
group.addTask { await f1() }
group.addTask { await f2() }
group.addTask { await f3() }
var total = 0
for await value in group {
total += value
}
return total
}
所有子任务:
离开 withTaskGroup:
👉 不会“偷偷活着的任务”
TaskGroup 的哲学是:
并发任务之间不共享可变状态,只通过结果汇合
子任务:
return 值父任务:
并发只发生在:
group.addTask收敛点是:
for await value in group这让代码在语义上可推理。
Parent Task
└─ TaskGroup
├─ Child Task 1
├─ Child Task 2
└─ Child Task 3
特点:
子任务都是:
| 行为 | 结果 |
|---|---|
| 父 task 被取消 | group 中所有子任务被取消 |
| 任一子任务抛错(throwing group) | 其余子任务全部取消 |
| 离开作用域 | 等待所有子任务完成 |
这是你问题的核心 👇
withTaskGroup(of: Int.self) { group in
group.addTask {
// 只能返回 Int
}
}
for await value in group {
// 这里是顺序执行的
}
var sum = 0
sum += value
你做不到:
var g: TaskGroup<Int>?
withTaskGroup(of: Int.self) { group in
g = group // ❌ 不允许
}
👉 这从根源上消灭了悬垂并发。
这避免了:
actor Store {
func loadAll() async {
await withTaskGroup(of: Item.self) { group in
for id in ids {
group.addTask {
await fetchItem(id)
}
}
for await item in group {
self.items.append(item) // actor 内,安全
}
}
}
}
| 特性 | TaskGroup | async let |
|---|---|---|
| 子任务数量 | 动态 | 静态 |
| 结果处理 | 流式 | 一次性 |
| 错误处理 | 可逐个 | 一起 |
| 适合场景 | 批量 / 不定量 | 少量固定 |
var sum = 0
withTaskGroup(of: Int.self) { group in
group.addTask { sum += 1 } // ❌ 数据竞争
}
子任务仍然是并发的。
不会。
如果你要限流,需要:
withTaskGroup { group in
// 自己控制 addTask 的节奏
}
或使用 semaphore / AsyncSemaphore。
TaskGroup 的设计目的,是在结构化并发模型下,
安全地表达“多个并发子任务 + 统一收敛”的计算模式。
它通过作用域约束、结果传递而非状态共享、串行消费、自动取消传播,
从语言和类型系统层面避免了数据竞争和失控并发。