Swift async let取消不生效:子任务抛错未触发另一并发子任务取消
问题原因解答
这不是版本Bug,也不存在遗漏的配置项,该行为完全符合Swift 并发模型中async let的设计逻辑,核心差异来自表达式的从左到右求值顺序与async let的自动取消触发规则。
async let 自动取消的触发规则
async let 绑定的子任务仅会在以下两种场景下被系统自动取消:
- 父任务本身被主动取消时,所有未执行完成的
async let子任务都会被取消 - 当
await某个async let的结果时,如果该子任务抛出错误,系统会自动取消所有还未被await过的其余async let子任务
两种写法的行为差异解释
原始写法 try await a + b
Swift 对加法表达式的求值顺序为从左到右,因此执行逻辑为:
- 先
await子任务a(computeA)的结果,此时子任务b虽然已经抛出错误,但还没有进入await流程,错误没有被抛出,不会触发取消逻辑 - 等待200ms后computeA执行完成,拿到a的返回值,才开始
await子任务b的结果 - 此时捕获到b抛出的错误,但所有
async let子任务都已经被await过,没有需要取消的任务,因此computeA的Task.isCancelled始终为false,和你的运行输出一致。
调整写法 try await b + a
求值顺序变为先处理b再处理a,执行逻辑为:
- 先
await子任务b(computeB)的结果,直接捕获到抛出的错误 - 此时子任务a还没有被
await过,符合自动取消规则,系统会立刻取消computeA的任务 - 因此computeA的
Task.isCancelled为true,符合你的预期。
符合预期的解决方案
如果你需要实现「任意子任务抛出错误时,立刻取消其余所有并发子任务」的逻辑,不需要依赖await顺序,推荐使用ThrowingTaskGroup替代async let,任务组自带错误传播时的全局取消逻辑,示例代码如下:
func checkCancellation() async throws { let c = try await withThrowingTaskGroup(of: Int.self) { group in group.addTask { try await computeA() } group.addTask { try await computeB() } let a = try await group.next()! let b = try await group.next()! return a + b } print("c = \(c)") }
内容的提问来源于stack exchange,提问作者user1046037
相关产品推荐
相关产品推荐

