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

Swift中如何等待多个并行异步调用全部完成后返回结果

并行批量保存实现方案

你可以根据需求选择以下两种实现方式,两种都能满足「所有任务并行执行、全部完成后返回结果」的要求。


方案1:ThrowingTaskGroup 实现(动态任务量首选)

这是Swift并发里处理动态数量并行任务的标准实现,自带错误传递、自动取消子任务的能力,是这类场景的首选方案:

static func save(files: [URL]) async throws -> [String] {
    try await withThrowingTaskGroup(of: (Int, String).self) { group in
        // 遍历文件时给每个任务绑定输入索引,保证最终结果顺序和输入一致
        for (index, fileURL) in files.enumerated() {
            group.addTask {
                let remoteURL = try await save(fileURL)
                return (index, remoteURL)
            }
        }

        // 初始化定长占位数组
        var resultList = Array<String?>(repeating: nil, count: files.count)
        // 逐次接收完成的任务结果,按索引放到对应位置
        for try await (index, remoteURL) in group {
            resultList[index] = remoteURL
        }

        // 所有任务完成后数组所有位置都有值,直接转换返回即可
        return resultList.map { $0! }
    }
}

这个方案的特性:

  • 所有保存任务完全并行执行,总耗时取决于最慢的单个保存任务,而非所有任务耗时累加
  • 任意一个任务抛出错误时,TaskGroup会自动取消所有其他正在运行的子任务,立即向上抛出错误,符合throwing函数的错误传播语义
  • 索引绑定的写法避免了任务完成先后导致的结果乱序问题,返回数组顺序和输入files数组完全对应

方案2:Task数组实现(轻量场景适用)

如果任务量不大,也可以手动创建Task实例存入数组,再统一等待结果返回,写法更简洁:

static func save(files: [URL]) async throws -> [String] {
    // 注意:必须先创建完所有Task实例,再统一await结果,否则会变成串行执行
    let tasks = files.map { fileURL in
        Task {
            try await save(fileURL)
        }
    }

    var resultList = [String]()
    // 按输入顺序依次获取每个任务的结果
    for task in tasks {
        resultList.append(try await task.value)
    }
    return resultList
}

这个方案的注意点:

  • 禁止在map闭包内直接await save(fileURL),否则会变成逐个串行执行,完全失去并行效果
  • 错误发生时不会自动取消其他已启动的任务,未完成的任务会继续在后台执行,如果你需要任务级联取消的能力,优先选择TaskGroup方案
  • 天然保证返回结果顺序和输入顺序一致

常见踩坑:不要写for url in files { results.append(try await save(url)) }这类循环内直接await的代码,这种写法是严格串行的,总耗时是所有文件保存耗时的总和。

内容的提问来源于stack exchange,提问作者Dannis Case

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:12:21