【Swift Concurrency】深入理解 `async let` 与 `TaskGroup`:并发任务的生命周期与错误传播机制

一、什么是 async let

async let 是 Swift 提供的一种结构化并发语法糖,用于并发地启动多个子任务,并延迟等待其结果。

✅ 基本用法

swift 复制代码
func fetchData() async {
    async let first = fetchPart1()
    async let second = fetchPart2()
    async let third = fetchPart3()

    let result = await (first, second, third)
    print(result)
}
  • 每个 async let 会创建一个子任务(child task)。
  • 子任务立即开始执行,不会阻塞当前任务。
  • 使用 await 获取结果时,按顺序等待(从左到右)。

✅ 支持任意表达式

swift 复制代码
async let number = 123
async let str = "Hello"

实际上,Swift 会将这些表达式包装为 ChildTask,并在后台并发执行。

二、什么是 TaskGroup?

TaskGroup 是 Swift 提供的动态并发任务创建机制,适合任务数量在运行时决定的场景。

✅ 示例:动态创建任务

swift 复制代码
func fetchData(count: Int) async {
    var results = [String]()

    await withTaskGroup(of: String.self) { group in
        for index in 0..<count {
            group.addTask {
                await self.fetchPart(index)
            }
        }

        for await result in group {
            results.append(result)
        }
    }

    print(results)
}
  • addTask 动态添加子任务。
  • for await 按完成顺序处理结果(谁先完成谁先处理)。
  • 也可以使用 group.next() 手动迭代。

三、生命周期机制对比

特性 async let TaskGroup
生命周期作用域 当前局部作用域(函数、do块等) withTaskGroup 闭包
正常退出时 自动取消并等待所有子任务 自动等待所有子任务(不取消)
异常退出时 自动取消并等待所有子任务 自动取消并等待所有子任务
是否支持动态任务数 ❌ 不支持 ✅ 支持
是否按完成顺序处理结果 ❌ 按声明顺序 await ✅ 按完成顺序

四、错误传播机制详解

async let 的错误传播

swift 复制代码
async let f = fast()
async let s = slow()

do {
    try await (f, s)
} catch {
    print("Caught error: \(error)")
}
  • 错误传播顺序取决于 await 的顺序。
  • 如果 fast() 先抛出错误,slow() 会被隐式取消并等待。
  • 如果 slow() 先完成但 fast() 先抛出错误,slow() 的错误不会被捕获。

✅ TaskGroup 的错误传播

swift 复制代码
try await withThrowingTaskGroup(of: Void.self) { group in
    group.addTask { try await fast() }
    group.addTask { try await slow() }

    for try await _ in group {
        // 处理结果
    }
}
  • 使用 for try await 时,第一个抛出的错误会立即传播。
  • 其余任务会被取消并等待。
  • 错误传播顺序与任务完成顺序无关,谁先抛谁传播。

五、实战建议:如何选择?

场景 推荐方式 原因
任务数量固定 async let 简洁、语法糖优雅
任务数量动态 TaskGroup 支持运行时添加任务
需要"fail fast" TaskGroup 错误传播更及时、可控
需要按顺序处理结果 async let 可控制 await 顺序
需要按完成顺序处理结果 TaskGroup AsyncSequence 自动支持

六、常见误区与注意事项

⚠️ 1. async let 不支持逃逸闭包

swift 复制代码
async let result = someAsyncFunc()
DispatchQueue.main.async {
    // ❌ 不能使用 result,生命周期已结束
}

⚠️ 2. 不 await 也会等待完成

swift 复制代码
async let f = slowTask()
print("End") // 仍会等待 f 完成后再退出作用域

⚠️ 3. 不支持"真正的 fire-and-forget"

  • 结构化任务总是会被等待。
  • 若需真正"放飞自我",请使用非结构化 Task:
swift 复制代码
Task.detached {
    await someAsyncFunc()
}

七、总结:一句话记住差异

async let 是固定并发任务的语法糖,生命周期绑定作用域,错误传播顺序依赖 await 顺序;

TaskGroup 是动态并发任务的管理器,生命周期绑定闭包,错误传播顺序更及时、可控。

相关推荐
QWQ___qwq6 小时前
My Swift笔记
swift
小蕾Java1 天前
IDEA快速上手指南!
java·intellij-idea·swift
山顶夕景2 天前
【LLM】基于ms-Swift大模型SFT和RL的训练实践
大模型·微调·swift·强化学习
HarderCoder3 天前
SwiftUI redraw 机制全景解读:从 @State 到 Diffing
swift
pixelpilot3 天前
Nimble:让SwiftObjective-C测试变得更优雅的匹配库
开发语言·其他·objective-c·swift
大熊猫侯佩3 天前
张真人传艺:Swift 6.2 Actor 隔离协议适配破局心法
swiftui·swift·apple
Dream_Ji5 天前
Swift入门(二 - 基本运算符)
服务器·ssh·swift
HarderCoder6 天前
Swift 6.1 `withTaskGroup` & `withThrowingTaskGroup` 新语法导读
ios·swift
HarderCoder6 天前
Swift 并发:Actor、isolated、nonisolated 完全导读
ios·swift
用户096 天前
Swift Feature Flags:功能切换的应用价值
面试·swiftui·swift