如何在纯Swift中顺序执行异步函数的多次调用
纯Swift实现异步函数串行执行方案
假设我们有一个异步函数:
func doAsyncWork() async throws { ... }
需要实现:多次调用该函数时,同一时间仅能有一个实例在执行;后续调用需进入队列等待,按FIFO顺序在前一次执行完成后依次运行;同时保证每个调用能正确获取自身执行的成功/错误结果。以下是纯Swift的实现方案:
核心实现:串行任务执行器
我们可以封装一个执行器类,通过Swift并发框架的Task管理任务队列:
class SerialAsyncExecutor { // 跟踪当前正在执行或等待执行的任务链 private var currentTask: Task<Void, Error>? // 绑定原始异步任务 private let work: () async throws -> Void init(work: @escaping () async throws -> Void) { self.work = work } // 对外暴露的串行执行方法 func execute() async throws { let newTask = Task { // 先等待前序任务完成(保证FIFO顺序,无论前序任务成功/失败) if let existingTask = self.currentTask { _ = await existingTask.result } // 执行当前任务 try await self.work() } // 更新任务链为新任务,确保后续调用能排队等待 self.currentTask = newTask // 等待当前任务完成,同步传播结果或错误 try await newTask.value } }
使用方式
将原始的doAsyncWork传入执行器,之后在任意位置调用execute()即可实现串行执行:
// 创建执行器并绑定原始异步任务 let executor = SerialAsyncExecutor(work: doAsyncWork) // 并发调用示例:三个任务会严格按调用顺序串行执行 Task { do { try await executor.execute() print("任务1执行完成") } catch { print("任务1执行失败:\(error)") } } Task { do { try await executor.execute() print("任务2执行完成") } catch { print("任务2执行失败:\(error)") } } Task { do { try await executor.execute() print("任务3执行完成") } catch { print("任务3执行失败:\(error)") } }
关键特性说明
- 严格FIFO顺序:每个新任务都会等待前序任务完成后再执行,完全遵循调用顺序。
- 错误独立传播:每个
execute()调用仅获取自身执行doAsyncWork的错误,前序任务失败不会阻止后续任务执行,仅会等待其完成。 - 无外部依赖:完全基于Swift原生并发API实现,无需引入第三方库。
- 线程安全增强:若需在多线程环境下调用,可将
SerialAsyncExecutor声明为actor,借助Swift并发的actor语义自动保证线程安全:
actor SerialAsyncExecutor { private var currentTask: Task<Void, Error>? private let work: () async throws -> Void init(work: @escaping () async throws -> Void) { self.work = work } func execute() async throws { let newTask = Task { if let existingTask = self.currentTask { _ = await existingTask.result } try await self.work() } self.currentTask = newTask try await newTask.value } }
内容的提问来源于stack exchange,提问作者Dominik Palo
相关产品推荐
相关产品推荐

