如何限制Swift TaskGroup中同时执行的并发任务数量
Swift 基于TaskGroup限制并发数的实现方法
核心实现逻辑
Swift 原生TaskGroup本身没有暴露设置最大并发数的接口,要手动控制并发量不需要引入第三方库,只要调整任务入组的节奏即可:
- 不要在初始化任务组时一次性把所有待执行任务全部入组
- 初始阶段仅向任务组添加和设定的最大并发数等量的任务
- 后续每收到1个任务完成的返回结果,立刻从待处理任务队列里取1个新任务补入组
- 整个执行周期内,同时处于运行状态的任务数会始终维持在你设定的阈值以内,不会出现一次性触发上百个下载请求的问题
适配图片下载场景的改造代码
以你需要的「最多同时下载10张图片」的需求为例,改造后的代码如下:
// 最大并发下载数量,可根据需求自行调整 let maxConcurrentDownloadCount = 10 func loadImageData(for assets: [PHAsset]) { Task { do { let imagesData = try await withThrowingTaskGroup(of: (id: String, data: Data).self) { group in // 记录当前已经加入任务组的资源索引 var currentIndex = 0 let totalCount = assets.count // 第一步:先把初始的最大并发数等量的任务加入组 while currentIndex < min(maxConcurrentDownloadCount, totalCount) { let asset = assets[currentIndex] group.addTask { return (id: asset.localIdentifier, data: try await self.imageData(for: asset)) } currentIndex += 1 } var dictionary = [String: Data]() // 第二步:每完成一个任务,就补一个新任务进组 for try await item in group { dictionary[item.id] = item.data print("Downloaded \(dictionary.count) of \(totalCount)") // 还有未处理的资源时,补加新任务 if currentIndex < totalCount { let asset = assets[currentIndex] group.addTask { return (id: asset.localIdentifier, data: try await self.imageData(for: asset)) } currentIndex += 1 } } return assets.compactMap { dictionary[$0.localIdentifier] } } print("Done") } catch { print(error) } } } func imageData(for asset: PHAsset) async throws -> Data { // 此处保留原来的PHImageManager适配async/await的逻辑即可 }
额外说明
- 这种实现完全是Swift并发框架原生支持的写法,没有用到任何黑魔法,系统依然会根据CPU、网络状态自动调度任务,只是把任务入组的节奏从「一次性全塞」改成了「完成一个补一个」
- 并发数不要设置得过高,图片下载场景建议根据网络环境设置在4~20之间即可,过高的并发反而会因为带宽抢占、系统线程调度开销导致整体下载速度变慢
- 现有逻辑完全兼容Swift并发的取消机制,父任务取消时任务组内所有正在执行和等待的任务都会被自动取消,不需要额外处理
内容的提问来源于stack exchange,提问作者Jordan H
相关产品推荐
相关产品推荐

