Swift中OperationQueue等待任意操作完成的最佳实践方法咨询
解决方案:解耦操作与队列,实现任意操作完成即取消其余任务
你的核心痛点是搜索操作与队列产生了不必要的耦合,操作只应专注于搜索逻辑,无需知晓所在队列。以下是两种更优雅的实现思路:
1. 基于原子状态标记 + 完成回调的方案
通过一个线程安全的原子布尔值追踪答案是否找到,所有操作共享这个状态,同时利用操作的completionBlock在第一个任务完成时触发队列取消,完全解耦操作与队列。
步骤1:实现线程安全的原子布尔类
用于安全地多线程读写"答案是否找到"的状态:
class AtomicBool { private let lock = NSLock() private var _value: Bool init(initialValue: Bool) { _value = initialValue } var value: Bool { get { lock.lock() defer { lock.unlock() } return _value } set { lock.lock() defer { lock.unlock() } _value = newValue } } // 尝试设置值,只有当前值不等于目标值时才修改,返回是否修改成功 func trySet(to newValue: Bool) -> Bool { lock.lock() defer { lock.unlock() } guard _value != newValue else { return false } _value = newValue return true } }
步骤2:重构搜索操作
操作仅持有原子状态的引用,专注于搜索逻辑:
class FindOperation: Operation { private weak var isAnswerFound: AtomicBool? private var _isFinished = false override var isFinished: Bool { get { _isFinished } set { willChangeValue(forKey: "isFinished") _isFinished = newValue didChangeValue(forKey: "isFinished") } } init(isAnswerFound: AtomicBool) { self.isAnswerFound = isAnswerFound super.init() } override func start() { // 先检查是否已被取消或答案已找到 guard !isCancelled, isAnswerFound?.value == false else { isFinished = true return } while !isFinished, !isCancelled, isAnswerFound?.value == false { // 执行你的搜索逻辑 // 示例:模拟随机找到答案的场景 if Int.random(in: 0...10000) == 5000 { isFinished = true // 尝试标记答案已找到(仅第一个成功的操作生效) _ = isAnswerFound?.trySet(to: true) } } isFinished = true } }
步骤3:外部协调队列与操作
在队列层面处理取消逻辑,操作无需感知队列:
let queue = OperationQueue() let coreCount = ProcessInfo.processInfo.activeProcessorCount queue.maxConcurrentOperationCount = coreCount let isAnswerFound = AtomicBool(initialValue: false) for _ in 0..<coreCount { let operation = FindOperation(isAnswerFound: isAnswerFound) // 给每个操作添加完成回调,第一个找到答案的操作触发队列取消 operation.completionBlock = { [weak queue, weak isAnswerFound] in guard let isAnswerFound = isAnswerFound, isAnswerFound.value else { return } queue?.cancelAllOperations() } queue.addOperation(operation) } // 等待所有操作完成(包括被取消的操作清理资源) queue.waitUntilAllOperationsAreFinished()
2. 基于信号量的高效等待方案
如果希望在第一个操作完成后立刻取消队列(无需等待所有操作自行检查状态),可以用DispatchSemaphore实现"等待任意操作完成"的逻辑,进一步提升效率:
let queue = OperationQueue() let coreCount = ProcessInfo.processInfo.activeProcessorCount queue.maxConcurrentOperationCount = coreCount let isAnswerFound = AtomicBool(initialValue: false) let completionSemaphore = DispatchSemaphore(value: 0) for _ in 0..<coreCount { let operation = FindOperation(isAnswerFound: isAnswerFound) operation.completionBlock = { [weak isAnswerFound, weak completionSemaphore] in guard let isAnswerFound = isAnswerFound else { return } // 只有第一个找到答案的操作会触发信号量 if isAnswerFound.trySet(to: true) { completionSemaphore?.signal() } } queue.addOperation(operation) } // 阻塞当前线程,直到第一个操作找到答案 completionSemaphore.wait() // 立刻取消队列中剩余的操作 queue.cancelAllOperations() // 等待所有操作完成资源清理 queue.waitUntilAllOperationsAreFinished()
核心优势
- 解耦操作与队列:搜索操作只负责业务逻辑,无需管理队列生命周期,符合单一职责原则。
- 线程安全:通过原子类确保多线程下状态读写的安全性,避免竞态条件。
- 灵活性:可以根据需求选择"等待第一个完成后取消"或"让操作自行检查状态退出"的模式。
内容的提问来源于stack exchange,提问作者davidf2281
相关产品推荐
相关产品推荐

