[英]How to assure that operations in an OperationQueue are finished one after another
執行相互依賴的OperationQueue
,可以使用OperationQueue
確保它們以正確的順序執行。 但是,是否也可以確保操作一個接一個地完成?
讓我們假設一個異步執行的方法,需要一些時間才能完成:
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(label: "operations").async
- 你的performOperation
方法在你內部異步調度print …; usleep …; success …
序列后立即退出print …; usleep …; success …
print …; usleep …; success …
print …; usleep …; success …
,為每個performOperation
調用創建的新調度隊列。 然后,在Grand Central Dispatch管理的工作線程池的不同線程上執行該序列的打印/睡眠/成功回調。
我認為你在這里可能會感到困惑的是認為反復說明DispatchQueue(label: "operations")
會使你獲得相同的串行調度隊列實例 - 事實並非如此,實際上你在每個調用時創建一個新的串行隊列。
BlockOperation
,也沒有理由在performOperation
創建或調度到串行調度隊列,因為BlockOperation
已經實現,以便在支持OperationQueue的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
請參閱此示例以優雅地了解BlockOperation 示例
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.