Swift中对应Kotlin协程、等待异步任务完成的实现方案
问题原因
你原有代码的核心问题有两点:
- 创建的两个
Task是独立的非结构化任务,不会被checkData函数的执行生命周期绑定,函数不会等待两个任务执行完成就会直接退出 - Swift的
Task优先级只是给系统调度器的调度权重参考,不是强制的执行顺序保证,高优先级任务不会阻塞低优先级任务的调度执行,因此会出现低优先级任务先执行完成的情况
可实现「等待所有并发任务完成后再执行后续逻辑」的方案
Swift并发模型本身提供了和Kotlin协程对齐的结构化并发能力,完全可以实现等效的任务等待、调度能力,常用方案如下:
方案1:使用withTaskGroup/withThrowingTaskGroup(推荐,结构化并发实现)
这是和Kotlin协程coroutineScope { async {}.awaitAll() }完全等效的实现,属于结构化并发范畴:任务组的生命周期和当前作用域绑定,作用域退出前会自动等待所有组内任务执行完成,同时会自动传递取消信号,也支持配置任务优先级。
示例代码:
func checkData(firstName: String) async { // 进入任务组作用域 await withTaskGroup(of: Void.self) { group in // 添加高优先级比对任务 group.addTask(priority: .high) { await compareFirstName(firstName: firstName) } // 添加低优先级上传任务 group.addTask(priority: .low) { await uploadFirstName(firstName: firstName) } // 无需手动写等待逻辑,作用域结束前会自动阻塞等待所有组内任务执行完毕 } // 执行到此处时,两个任务已经全部完成,可以执行后续逻辑 await yourFollowUpLogic() }
注意:如果业务要求
compareFirstName必须100%在uploadFirstName之前执行完成,不要使用并发调度,直接按顺序调用await即可,示例:func checkData(firstName: String) async { // 严格顺序执行,前一个执行完成才会启动下一个 await compareFirstName(firstName: firstName) await uploadFirstName(firstName: firstName) // 后续逻辑 await yourFollowUpLogic() }
如果任务可能抛出错误,把withTaskGroup替换为withThrowingTaskGroup即可,错误会自动向外抛出。
方案2:手动持有Task句柄调用value等待
如果需要更灵活的任务控制(比如单独取消某个任务),可以手动创建Task并持有引用,通过await task.value等待任务完成,等效于Kotlin协程的Job.join()/Deferred.await()。
示例代码:
func checkData(firstName: String) async { // 创建任务并持有句柄 let compareTask = Task(priority: .high) { await compareFirstName(firstName: firstName) } let uploadTask = Task(priority: .low) { await uploadFirstName(firstName: firstName) } // 等待两个任务全部执行完成 _ = await compareTask.value _ = await uploadTask.value // 执行后续逻辑 await yourFollowUpLogic() }
注意:该方案属于非结构化并发实现,不会自动传递取消信号,如果当前上下文被取消,需要手动调用cancel()方法取消两个子任务,非特殊场景优先使用方案1的任务组实现。
扩展:获取并发任务的返回值
如果需要像Kotlin协程的async一样拿到每个并发任务的返回结果,直接在任务组中遍历结果即可,还支持在某个任务失败时提前取消所有剩余任务:
func checkData(firstName: String) async -> Bool { let checkPassed = await withTaskGroup(of: Bool.self) { group in group.addTask(priority: .high) { await compareFirstName(firstName: firstName) } group.addTask(priority: .low) { // 上传任务返回是否上传成功 return await uploadFirstName(firstName: firstName) } for await taskResult in group { if !taskResult { // 任意任务失败,取消所有剩余任务直接返回 group.cancelAll() return false } } return true } return checkPassed }
内容的提问来源于stack exchange,提问作者Steven-Carrot
相关产品推荐
相关产品推荐

