Ожидание только одной операции в 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
, потому что это то, что вы сделали в своем фрагменте кода, но, очевидно, никто не ждет от основного потока. Возможно, вы отправили весь этот блок кода в фоновую очередь, но пропустили это в своем вопросе?