Swift - запускать 1000 асинхронных задач со спящим через каждые 50 - как общаться между собой DispatchGroups
Мне нужно выполнить 1000 асинхронных вычислений. Поскольку у API есть ограничение в 50 запросов / мин, мне приходится разбивать его на блоки по 50 и ждать минуту после обработки одного блока. В конце концов я хочу распечатать результаты.
resultsArray = [Double]()
// chunked is an extension
points.chunked(into: 50).forEach { pointsChunk in
pointsChunk.forEach { pointsPair
// this function is async
service.calculate(pointsPair) { result in
resultsArray.append(result)
}
}
// wait for a minute before continuing with the next chunk
}
// after all 1000 calculations are done, print result
print(resultsArray)
Я пытался найти решение, используя DispatchGroup
но боролся с тем, как включить таймер:
let queue = DispatchQueue(label: "MyQueue", attributes: .concurrent)
let chunkGroup = DispatchGroup()
let workGroup = DispatchGroup()
points.chunked(into: 50).forEach { pointsChunk in
chunkGroup.enter()
pointsChunk.forEach { routePointsPair in
workGroup.enter()
// do something async and in the callback:
workGroup.leave()
}
workGroup.notify(queue: queue) {
do { sleep(60) }
chunkGroup.leave()
}
}
chunkGroup.notify(queue: .main) {
print(resultArray)
}
Это просто выполняет все фрагменты одновременно, а не с задержкой на 60 секунд.
1 ответ
То, что я реализовал в подобной ситуации, - это ручная приостановка и возобновление моей последовательной очереди.
моя ссылка на очередь:
public static let serialQueue = DispatchQueue(label: "com.queue.MyProvider.Serial")
func serialQueue() -> DispatchQueue {
return MyProvider.serialQueue
}
приостановить очередь:
func suspendSerialQueue() -> Void {
self.serialQueue().suspend()
}
возобновить очередь после задержки:
func resumeSerialQueueAfterDelay(seconds: Double) -> Void {
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + seconds) {
self.serialQueue().resume()
}
}
Таким образом, у меня есть полный контроль над тем, когда я приостанавливаю и возобновляю очередь, и могу равномерно распределить многие вызовы API в течение более длительного периода времени.
self.serialQueue().async {
self.suspendSerialQueue()
// API call completion block {
self.resumeSerialQueueAfterDelay(seconds: delay)
}
}
Не уверен, что это то, что вы искали, но, возможно, вы сможете адаптировать мой пример к своим потребностям.