Ожидание только одной операции в OperationQueue

При использовании OperationQueues в Swift, как лучше всего дождаться завершения любой операции в очереди, в отличие от обычного требования ожидания завершения всех операций через?

Мотивация — параллельный алгоритм поиска, в котором любая из операций поиска имеет равные шансы найти ответ, и в этот момент я хочу отменить все другие теперь избыточные операции, которые ищут то же самое.

Моя первоначальная наивная реализация состоит в том, чтобы передавать каждой операции ссылку на очередь, чтобы позволить первой завершить вызовна нем, что приводит к чему-то в следующем виде:

      class FindOperation: Operation {
    private weak var queue: OperationQueue?
    private var answerFound = false
    override var isFinished: Bool { answerFound }

    init(queue: OperationQueue) {
        self.queue = queue
    }

    override func start() {
        while(!answerFound && !self.isCancelled) {
            // Do some intensive work to find our answer
        }
        
        // We've found our answer so tell the queue to cancel other
        // operations, which were all looking for the same thing
        queue?.cancelAllOperations()
    }
}

...

let queue = OperationQueue()
let coreCount = ProcessInfo.processInfo.activeProcessorCount
queue.maxConcurrentOperationCount = coreCount

for _ in 0..<coreCount {
    let findOperation = FindOperation(queue: queue)
    queue.addOperation(findOperation)
}

queue.waitUntilAllOperationsAreFinished()

Это кажется неправильным, поскольку операциям определенно не нужно знать о своей собственной очереди.

Я не могу найти ссылку вдокументы, которые относятся к этому сценарию. Есть ли более приятный способ дождаться завершения только одной операции?

1 ответ

Звонящий может установитьдля операций. Он хранит весь код, связанный с очередями операций, в одной области в более широкой кодовой базе.

      let queue = OperationQueue()

let operations = (0..<count).map { _ in
    let operation = FindOperation()
    operation.completionBlock = { queue.cancelAllOperations() }
    return operation
}

queue.addOperations(operations, waitUntilFinished: true)

Обратите внимание: я смягчаю гонку между добавлением операций и их отменой, (а) сначала создавая все операции; а затем (b) добавление их в очередь только после выполнения операций (и соответствующих имcompletionBlockзакрытие) были установлены.

Кроме того, помните, что в синхронных операциях, как здесь, один переопределяетmain, нет . Мы только переопределяемstartпри написании операции, которая сама по себе оборачивает асинхронную задачу (и тогда, конечно, нужно еще и все КВО делать дляisExecuting,isFinished, и т. д.).

Наконец, я установилwaitUntilFinished, потому что это то, что вы сделали в своем фрагменте кода, но, очевидно, никто не ждет от основного потока. Возможно, вы отправили весь этот блок кода в фоновую очередь, но пропустили это в своем вопросе?

Другие вопросы по тегам