Swift异步Task中更新CLI进度条出现并发修改错误如何解决?
错误原因
该报错是Swift并发安全检查触发的:你定义的ProgressBar是可变结构体,而Task闭包属于并发执行的代码,编译器无法保证你在并发上下文中修改外部bar变量的操作是线程安全的,因此直接拦截编译。
解决方案1:主Actor调度更新(推荐用于CLI场景)
CLI进度条的渲染属于终端输出类操作,本身需要在主线程执行避免输出乱序,你可以直接将进度条更新操作调度到主Actor执行即可:
var bar = ProgressBar(count: 100) let waiter = Task { do { for try await output in session.outputs { switch output { case .requestProgress(let request, let fractionComplete): let progress = Int(fractionComplete * 100) // 将修改操作切到主Actor执行,保证线程安全 await MainActor.run { bar.setValue(progress) } } } } catch { logger.error("Output: ERROR = \(String(describing: error))") Foundation.exit(0) } }
解决方案2:Actor封装状态管理
如果你需要脱离主线程管理进度状态,可以自定义Actor来封装进度条的所有变更操作,保证所有修改串行执行:
// 自定义Actor保证进度条修改线程安全 actor ProgressStateManager { private var bar: ProgressBar init(totalCount: Int) { bar = ProgressBar(count: totalCount) } func update(fractionComplete: Double) { bar.setValue(Int(fractionComplete * 100)) } } // 调用侧代码 let progressManager = ProgressStateManager(totalCount: 100) let waiter = Task { do { for try await output in session.outputs { switch output { case .requestProgress(let request, let fractionComplete): // 异步调用Actor的更新方法,自动保证线程安全 await progressManager.update(fractionComplete: fractionComplete) } } } catch { logger.error("Output: ERROR = \(String(describing: error))") Foundation.exit(0) } }
内容的提问来源于stack exchange,提问作者Alexander Hörl
相关产品推荐
相关产品推荐

