是否可以将DispatchQueue.concurrentPerform指定为DispatchQueue?

时间:2019-02-19 21:21:46

标签: swift grand-central-dispatch

dispatch_apply将调度队列作为参数,使您可以选择在哪个队列上执行该块。

我的理解是,Swift中的DispatchQueue.concurrentPerform旨在代替dispatch_apply。但是此函数不将调度队列作为参数。谷歌搜索之后,我发现this GCD tutorial的代码如下:

let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: addresses.count) { index in
    // do work here
}

并解释:

  

此实现包括一个奇怪的代码行:let _ = DispatchQueue.global(qos: .userInitiated)。调用此命令会导致GCD对并发调用使用服务质量为.userInitiated的队列。

我的问题是,这实际上可以用来指定QoS吗?如果可以,怎么办?

对于我来说,没有办法为此指定队列是有意义的,因为在这种情况下,串行队列没有意义,并且鉴于这是同步阻塞功能,只有最高的QoS才有意义。但是我找不到任何文档说明为什么可以使用dispatch_apply指定队列,而不能使用DispatchQueue.concurrentPerform指定队列。

1 个答案:

答案 0 :(得分:3)

作者尝试指定队列服务质量(QoS)的尝试不正确。 concurrentPerform会使用当前队列的QoS。您可以通过跟踪源代码来确认这一点:

  1. concurrentPerform呼叫_swift_dispatch_apply_current

  2. _swift_dispatch_apply_currentdispatch_apply,即0调用DISPATCH_APPLY_AUTO,即defined as a ...

      

    ...要传递给dispatch_apply()dispatch_apply_f()的常量,以请求系统自动使用与当前线程的配置尽可能匹配的工作线程。

         

    提交用于并行调用的块时,将此常量作为queue参数传递将自动使用与调用者的服务质量最紧密匹配的全局并发队列。

  3. 这也可以通过在dispatch_apply调用dispatch_apply_f之后进行确认,其中使用DISPATCH_APPLY_AUTO会导致对_dispatch_apply_root_queue的调用。如果继续翻滚swift-corelibs-libdispatch的兔子洞,您会发现它实际上确实使用了与当前线程相同的QoS全局队列。

最重要的是,指定QoS的正确方法是将对concurrentPerform的呼叫分派到所需的队列,例如:

DispatchQueue.global(qos: .userInitiated).async {
    DispatchQueue.concurrentPerform(iterations: 3) { (i) in
        ...
    }
}

通过添加断点并查看Xcode调试器中的队列,可以很容易地凭经验验证这一点:

enter image description here


不用说,添加let _ = ...的建议是不正确的。请考虑以下内容:

DispatchQueue.global(qos: .utility).async {
    let _ = DispatchQueue.global(qos: .userInitiated)

    DispatchQueue.concurrentPerform(iterations: 3) { (i) in
        ...
    }
}

这将以“实用程序” QoS运行,而不是“用户启动”。

同样,这很容易根据经验进行验证:

enter image description here


有关DISPATCH_APPLY_AUTOconcurrentPerform的讨论,请参见WWDC 2017视频Modernizing Grand Central Dispatch