You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:45:19