首页 > 解决方案 > Swift - 每 50 次后使用睡眠者运行 1000 个异步任务 - 如何通信 btw 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)

我确实尝试使用 using 找到解决方案,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 秒。

标签: iosswiftasynchronousdispatchgroup

解决方案


我在类似情况下实现的是手动挂起和恢复我的串行队列。

我的队列参考:

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

不确定这是否是您正在寻找的,但也许您可以根据您的需要调整我的示例。


推荐阅读