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)
   }
}

Не уверен, что это то, что вы искали, но, возможно, вы сможете адаптировать мой пример к вашим потребностям.


Есть идеи?

10000