1️⃣ 核心原则
Task cancellation 是协作式的。你不能强制杀掉任务,而是需要在
async函数中主动检查取消状态并安全退出。
优雅处理的目标:
- 避免无用计算浪费 CPU
- 及时释放资源(文件、网络、内存)
- 不破坏结构化并发
2️⃣ 检查取消的基本方法
① 使用 Task.checkCancellation()
func doWork() async throws {
for i in 0..<1000 {
try Task.checkCancellation() // 检查取消
await doStep(i)
}
}
- 如果任务已取消 → 抛出
CancellationError - 异步调用者可捕获或让上层继续传播
② 使用 Task.isCancelled 手动判断
func doWork() async {
for i in 0..<1000 {
if Task.isCancelled {
print("Task cancelled, exit early")
return
}
await doStep(i)
}
}
- 不抛异常,只是提前返回
- 更适合非 throwing 函数
3️⃣ 使用 withTaskCancellationHandler 做清理
- 用于确保任务取消时可以执行资源释放操作
func doWork() async {
await withTaskCancellationHandler {
print("Cleaning up resources on cancellation")
} operation: {
for i in 0..<1000 {
try? Task.checkCancellation()
await doStep(i)
}
}
}
operation执行任务主体- 取消时会执行 handler → 清理文件、网络连接等
4️⃣ 异步挂起点自然检查取消
- 任何
await都会自动检查任务取消状态:
func downloadFile() async throws -> Data {
let data = try await URLSession.shared.data(from: url).0
return data
}
- 如果任务被取消 →
await会立即抛出CancellationError - 你无需额外检查,除非在 CPU 密集循环中
5️⃣ CPU 密集型任务的处理技巧
- CPU 密集循环不会自动响应取消 → 必须显式调用
Task.checkCancellation()
func heavyCompute() async throws -> Int {
var sum = 0
for i in 0..<1_000_000 {
try Task.checkCancellation() // 手动检查
sum += i
}
return sum
}
- 避免无用计算浪费 CPU
- 保持应用响应性
6️⃣ 综合示例
func processItems(_ items: [Int]) async throws {
try await withTaskCancellationHandler {
print("Cleaning up resources...")
} operation: {
for item in items {
try Task.checkCancellation() // 检查取消
await process(item)
}
}
}
- 检查取消 → 协作式响应
- withTaskCancellationHandler → 优雅释放资源
- await → 挂起点自动响应取消
7️⃣ 面试必背总结
Task cancellation 是协作式的,async 函数必须主动检查取消状态。
检查方式:
Task.checkCancellation()→ 抛CancellationErrorTask.isCancelled→ 提前返回资源释放:
withTaskCancellationHandler在取消时执行清理await 自然挂起点会自动响应取消,但 CPU 密集循环需手动检查
优雅处理取消可提高应用响应性并防止资源泄漏