我有一组异步执行的请求。然而,每个下一个请求只有在前一个请求完成后才能开始(由于数据依赖性)。
由于所有请求都应按正确顺序完成,DispatchGroup()
似乎没有用。
我目前实施了DispatchSemaphore()
,但我觉得这不是最好的解决方案,因为我想确保所有请求都在后台执行。
let semaphore = DispatchSemaphore(value: requests.count)
for request in requests {
apiManager().performAsyncRequest(request, failure: { error in
print(error); semaphore.signal()
}) { print(“request finished successful”)
// Next request should be performed now
semaphore.signal()
}
}
semaphore.wait()
有更好的方法来执行这个吗?
注意: 根据下面某个答案的实现,我遇到了 apiManager()
不是线程安全的问题 (由于使用了 Realm 数据库)。
为了保持这个问题的清晰,并考虑到以线程安全方式考虑答案,需要一个线程安全定义的 performAsyncRequest
:
public func performAsyncRequest(_ requestNumber: Int, success: @escaping (Int) -> Void)->Void {
DispatchQueue(label: "performRequest").async {
usleep(useconds_t(1000-requestNumber*200))
print("Request #\(requestNumber) starts")
success(requestNumber)
}
}
使用DispatchSemaphore
的解决方案
let semaphore = DispatchSemaphore(value: 1)
DispatchQueue(label: "requests").async {
for requestNumber in 0..<4 {
semaphore.wait()
performAsyncRequest(requestNumber) { requestNumber in
print("Request #\(requestNumber) finished")
semaphore.signal()
}
}
}
应输出如下结果:
Request #0 starts
Request #0 finished
Request #1 starts
Request #1 finished
Request #2 starts
Request #2 finished
Request #3 starts
Request #3 finished
操作失败,错误信息为Operation
var operations = [Operation]()
for requestNumber in 0..<4 {
let operation = BlockOperation(block: {
performAsyncRequest(requestNumber) { requestNumber in
DispatchQueue.main.sync {
print("Request #\(requestNumber) finished")
}
}
})
if operations.count > 0 {
operation.addDependency(operations.last!)
}
operations.append(operation)
}
let operationQueue = OperationQueue.main
operationQueue.addOperations(operations, waitUntilFinished: false)
输出不正确的情况:
Request #0 starts
Request #1 starts
Request #2 starts
Request #3 starts
Request #0 finished
Request #3 finished
Request #2 finished
Request #1 finished
我个人认为,使用 Operation
也应该可以实现这个功能,但我不确定它是否比使用 DispatchSemaphore
更好。