为什么 DispatchQueue 不尊重 QoS?

Why does DispatchQueue not respect QoS?

我正在尝试 运行 主队列中的多个任务,其中一些任务比其他任务更紧急。我正在使用 DispatchQoS 来执行此操作:

func enqueue(_ prio: Int) {
  let qos = DispatchQoS(qosClass: .userInteractive, relativePriority: prio)
  DispatchQueue.main.async(qos: qos) {
    NSLog("\(prio)")
  }
}

for i in 1...5 {
  for prio in -15...0 {
    enqueue(prio)
  }
}

我预计会看到五个零,然后是五个 -1,然后是五个 -2,依此类推。

但是我得到了:

-15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0

换句话说,调度队列按照任务入队的顺序执行任务,忽略优先级。


然后我尝试了不同的 QoS 类 而不是不同的 relativePriority:

func enqueue(_ qos: DispatchQoS) {
  DispatchQueue.main.async(qos: qos) {
    NSLog("\(qos.qosClass)")
  }
}

for i in 1...10 {
  enqueue(.background)
  enqueue(.utility)
  enqueue(.userInitiated)
  enqueue(.userInteractive)
}

但任务再次按入队顺序执行,忽略QoS。

如何让调度队列遵守 QoS?我的目标是 运行 主队列中的某些任务的优先级低于其他任务。

在 WWDC 2016 视频 Concurrent Programming with GCD in Swift 3 中,他们提到当您将某些内容添加到具有更高优先级的队列时,它不会 "jump the queue",而是使用 QoS 来解决优先级反转(例如,它可以使用它来增加队列中先前任务的优先级,以满足高 QoS 的后续任务,而不是改变串行队列中任务的顺序。

此外,我建议您不要在主队列中测试此类内容。这是一个带有专用线程的特殊串行队列,因此它对于检查 QoS 如何影响任务的调度和优先级并不是很有用。我建议创建您自己的并发队列来测试 QoS 问题。此外,如果您将任务添加到并发队列,它们通常必须足够实质且数量足够多,才能看到任何可辨别的模式。

最后,我鼓励您观看 WWDC 2015 视频 Building Responsive and Efficient Apps with GCD,因为它更详细地介绍了 QoS。上述 2016 年视频适合 Swift 3 个具体观察,但它实际上是建立在 2015 年视频中 QoS 讨论的基础上。

原来解决方案是使用OperationQueue:

let operation = BlockOperation(block: self.doSomething)

operation.queuePriority = .low

OperationQueue.main.addOperation(operation)

然后我可以连续执行低优先级任务,一个接一个,而不会使 UI 无响应。

感谢 Rob 指出为什么 DispatchQueues 不尊重优先级。