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

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

Другие вопросы по тегам