When using OperationQueues in Swift, what's the best-practise way to wait until any operation in the queue has completed, as opposed to the usual requirement of waiting until all have completed via waitUntilAllOperationsAreFinished()
?
The motivation is a concurrent search algorithm, in which any one of the search operations has an equal chance of finding the answer, at which point I want to cancel all of the other now-redundant operations which are looking for the same thing.
My initial naive implementation is to pass each operation a reference to the queue to allow the first to finish to call cancelAllOperations()
on it, resulting in something of the following form:
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()
This feels wrong since operations definitely shouldn't need to know about their own queue.
I can find no reference in the OperationQueue
docs that address this scenario. Is there a nicer way to wait for only one operation to complete?