Swift异步环境下用Semaphore控制并发下载的问题求助
Swift异步批量下载:限制并发数并等待全部完成
在Swift Concurrency体系下,DispatchSemaphore的wait()是阻塞式调用,完全不适用于async函数——这会破坏异步非阻塞的设计原则,也是你遇到问题的核心原因。正确的方案是使用**TaskGroup**,它原生支持并发数限制,且能自动等待所有任务完成。
修正后的代码实现
func downloadAllFiles() async -> String { // 生成10个待下载URL let urls = Array(repeating: "https://google.com", count: 10) // 通过TaskGroup控制并发,最多同时运行3个任务 await withTaskGroup(of: Void.self) { group in // 设置最大并发数 group.maxConcurrentTaskCount = 3 for url in urls { // 向任务组添加下载任务 group.addTask { let web = await MWeb.call(url: url) // 此处可添加下载结果的处理逻辑(如本地存储、日志记录等) } } // TaskGroup会自动等待所有任务执行完毕,无需额外等待逻辑 } return "所有文件下载完成" }
关键细节说明
- 替代DispatchSemaphore:
TaskGroup的maxConcurrentTaskCount直接实现了并发数限制,完全符合Swift异步编程模型,不会阻塞线程。 - 自动等待全部任务:
withTaskGroup的闭包会一直等到所有添加的任务执行完毕才会退出,完美解决你需要等待10个文件全部处理完成的需求。 - 优化任务管理:放弃
Task.detached的独立任务创建方式,TaskGroup中的任务与当前上下文关联,优先级继承自父任务,不会出现"lower QoS thread"警告(如需指定优先级,可通过addTask(priority:)参数设置)。
扩展:收集下载结果
如果需要返回所有下载的成功/失败状态,可以调整TaskGroup的输出类型:
func downloadAllFiles() async -> [Result<Data, Error>] { let urls = Array(repeating: "https://google.com", count: 10) return await withTaskGroup(of: Result<Data, Error>.self) { group in group.maxConcurrentTaskCount = 3 var results: [Result<Data, Error>] = [] for url in urls { group.addTask { do { let data = try await MWeb.call(url: url) // 假设MWeb.call抛出错误 return .success(data) } catch { return .failure(error) } } } // 遍历收集所有任务结果 for await result in group { results.append(result) } return results } }
内容的提问来源于stack exchange,提问作者Ernie Thomason
相关产品推荐
相关产品推荐

