执行相互依赖的操作时,可以使用OperationQueue确保它们以正确的顺序执行.但是,是否也可以确保操作一个接一个地完成? 让我们假设一个异步执行的方法,需要一些时间才能完成: public
让我们假设一个异步执行的方法,需要一些时间才能完成:
public func performOperation(_ number: Int, success: @escaping (Int) -> Void)->Void { DispatchQueue(label: "operations").async { print("Operation #\(number) starts") usleep(useconds_t(1000-number*200)) // Block thread for some time success(number) } }
操作和依赖项创建如下:
let operationQueue = OperationQueue.main for operationNumber in 0..<4 { // Create operations as an example let operation = BlockOperation(block: { performOperation(operationNumber) { number in DispatchQueue.main.sync { print("Operation #\(number) finished") } } }) operation.name = "Operation #\(operationNumber)" if operationNumber > 0 { operation.addDependency(operationQueue.operations.last!) // Print dependencies print("\(operation.name!) should finish after \(operation.dependencies.first!.name!)") } operationQueue.addOperation(operation) }
使用以下输出:
Operation #1 should finish after Operation #0 Operation #2 should finish after Operation #1 Operation #3 should finish after Operation #2 Operation #0 starts Operation #1 starts Operation #2 starts Operation #3 starts Operation #0 finished Operation #3 finished Operation #2 finished Operation #1 finished
这显然是不正确的.似乎OperationQueue只确保操作以正确的顺序启动(而不是一个接一个地完成).
尽管可以使用DispatchSemaphore执行此操作,但我想知道是否也可以使用OperationQueue.
我认为你在这里可能会感到困惑的是认为反复说明DispatchQueue(标签:“操作”)会使你获得相同的串行调度队列实例 – 事实并非如此,实际上你在每个调用时创建一个新的串行队列.
另外,也没有理由在performOperation中创建或调度到串行调度队列,因为BlockOperation已经实现,以便在支持OperationQueue(the concurrency is also possible to limit)的GCD调度队列上同时执行块.在我的例子中,我要做的是使用OperationQueue()构造一个新的OperationQueue(而不是使用在主队列上调度工作的OperationQueue.main),然后异步地将成功回调调度到主队列.
这个稍微修改过的例子向您展示了操作执行确实遵循了依赖关系(我没有实现上面的OperationQueue相关建议,它可以说是你提出的问题的旁边):
public func performOperation(_ number: Int, success: @escaping (Int) -> Void)->Void { print("Operation #\(number) starts") usleep(useconds_t(1000-(number*50))) // Block thread for some time success(number) } … let operationQueue = OperationQueue.main for operationNumber in 0..<8 { // Create operations as an example let operation = BlockOperation(block: { self.performOperation(operationNumber) { number in print("Operation #\(number) finished") } }) operation.name = "Operation #\(operationNumber)" if operationNumber > 0 { operation.addDependency(operationQueue.operations.last!) // Print dependencies print("\(operation.name!) should finish after \(operation.dependencies.first!.name!)") } operationQueue.addOperation(operation) }
这将输出……
Operation #1 should finish after Operation #0 Operation #2 should finish after Operation #1 Operation #3 should finish after Operation #2 Operation #4 should finish after Operation #3 Operation #5 should finish after Operation #4 Operation #6 should finish after Operation #5 Operation #7 should finish after Operation #6 Operation #0 starts Operation #0 finished Operation #1 starts Operation #1 finished Operation #2 starts Operation #2 finished Operation #3 starts Operation #3 finished Operation #4 starts Operation #4 finished Operation #5 starts Operation #5 finished Operation #6 starts Operation #6 finished Operation #7 starts Operation #7 finished