如何让被非异步函数f1触发的异步函数f2按顺序串行执行?
解决方案
你可以通过维护串行任务队列的方式实现f2的按序执行,有两种常用实现方案:
方案1:简易Task串接实现
如果你的f1只会在主线程被调用,不需要处理多线程竞态,可以用最简单的任务串接方式:
// 维护在类/全局作用域,记录上一次f2的执行任务 private var lastF2Task: Task<Void, Error>? // 你无法控制的f1调用逻辑,只需要修改内部的Task实现 func f1() { lastF2Task = Task { [weak lastF2Task] in // 等待上一次f2执行完成,忽略前序任务的错误 if let previousTask = lastF2Task { _ = try? await previousTask.value } // 执行当前f2 try await f2() } } func f2() async throws {}
- 逻辑说明:每次触发新的
f2任务时,都会先等待前一次任务执行结束(无论前一次执行成功还是失败),再启动当前任务,天然保证串行顺序。 - 注意:如果
f1可能在多线程环境被调用,直接读写lastF2Task会有竞态风险,推荐使用下面的Actor隔离方案。
方案2:Actor隔离安全队列(推荐)
用Actor隔离任务队列的状态,避免多线程竞态,适配所有调用场景:
// 串行任务队列Actor,保证状态修改线程安全 actor F2SerialQueue { private var lastTask: Task<Void, Error>? func addTask(_ operation: @escaping () async throws -> Void) { lastTask = Task { [weak lastTask] in // 等待前序任务完成 if let prevTask = lastTask { _ = try? await prevTask.value } try await operation() } } } // 全局初始化队列实例 private let f2Queue = F2SerialQueue() func f1() { Task { // 将f2加入串行队列等待执行 await f2Queue.addTask(f2) } } func f2() async throws {}
如果需要处理f2执行时抛出的错误,把代码里的try?替换为正常的try-catch逻辑即可。
内容的提问来源于stack exchange,提问作者user1046037
相关产品推荐
相关产品推荐

