You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 对加法表达式的求值顺序为从左到右,因此执行逻辑为:

  1. 先await子任务a(computeA)的结果,此时子任务b虽然已经抛出错误,但还没有进入await流程,错误没有被抛出,不会触发取消逻辑
  2. 等待200ms后computeA执行完成,拿到a的返回值,才开始await子任务b的结果
  3. 此时捕获到b抛出的错误,但所有async let子任务都已经被await过,没有需要取消的任务,因此computeA的Task.isCancelled始终为false,和你的运行输出一致。

调整写法 try await b + a

求值顺序变为先处理b再处理a,执行逻辑为:

  1. 先await子任务b(computeB)的结果,直接捕获到抛出的错误
  2. 此时子任务a还没有被await过,符合自动取消规则,系统会立刻取消computeA的任务
  3. 因此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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 00:42:03