【问题标题】:target parameter in DispatchQueueDispatchQueue 中的目标参数
【发布时间】:2017-03-30 19:06:36
【问题描述】:

在 Swift 3 中,创建 DispatchQueue 实例:

DispatchQueue(label: String,
              qos: DispatchQoS,
              attributes: DispatchQueue.Attributes,
              autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, 
              target: DispatchQueue?)

我看到StackOverFlow的示例代码,可以是nil,.global()或者.main,这个target参数是什么意思?

我猜 .main 意味着队列将在主线程上运行,但是 .nil 或 .global() 呢?

【问题讨论】:

    标签: swift queue dispatch


    【解决方案1】:

    TLDR:指定目标队列将为您的队列提供最低 QoS,并将所有块重定向到目标队列,同时保留队列的语义。

    例如,考虑队列 A 是并发的,队列 B 是串行的,以 A 为目标:

    // serial A -> targets concurrent B
    
    // concurrent queue A
    let a = DispatchQueue(label: "A", attributes: .concurrent)
    
    // serial queue B targeting concurrent queue A
    let b = DispatchQueue(label: "B", target: a)
    
    // next two blocks will be executed concurrently on A
    a.async {
        print("1")
    }
    a.async {
        print("2")
    }
    
    // next two blocks will be executed serially on A
    b.async {
        print("3")
    }
    b.async {
        print("4")
    }
    

    https://developer.apple.com/documentation/dispatch/dispatchobject/1452989-settarget

    将所有块从当前调度队列重定向到指定的目标队列。使用目标队列将工作从几个不同的队列重定向到一个队列。您可以这样做以最小化您的应用程序使用的线程总数,同时仍保留您需要的执行语义。如果调度队列有目标队列,系统不会将线程分配给调度队列,除非该目标队列是全局并发队列。

    目标队列定义了块的运行位置,但它不会改变当前队列的语义。即使底层目标队列是并发的,提交到串行队列的块仍然串行执行。此外,您不能在不存在的情况下创建并发。如果一个队列和它的目标队列都是串行的,向两个队列提交块不会导致这些块同时运行。这些块仍然按照目标队列接收它们的顺序连续运行。

    调度队列从其目标队列继承最低服务质量级别。

    【讨论】:

      【解决方案2】:

      目标用于设置目标队列层次结构。它不适用于 QoS。它用于控制线程数和目标队列层次结构。

      QoS 和您要创建的队列的特征将保持不变。但是这样做,性能会有所不同。如需更多信息,请参阅 WWDC 视频。

      【讨论】:

        【解决方案3】:

        没有关于 Swift 的文档,所以我退回到 GCD 的旧文档。我发现的最接近的是函数dispatch_set_target_queue

        对象的目标队列负责处理该对象。目标队列确定调用对象终结器的队列。此外,修改某些对象的目标队列会改变它们的行为:

        调度队列:

        调度队列的优先级继承自其目标队列。使用dispatch_get_global_queue函数来获取一个合适的目标队列,具有所需的优先级。

        如果您将块提交到串行队列,并且串行队列的目标队列是不同的串行队列,则该块不会与提交到目标队列或具有相同目标队列的任何其他队列的块同时调用。

        看起来target 队列做了两件事:

        1. 为您的新队列提供优先级
        2. 执行队列中所有对象的终结器 (deinit)

        在行之间读取,您的队列和目标队列之间存在一些同步。我目前没有 Xcode,所以无法测试。

        【讨论】:

        • 1.为您的新队列提供优先级。 -> 那么 qos 属性是做什么的。
        【解决方案4】:

        目标被苹果解释为:

        "一个调度队列的优先级是从它的目标队列继承而来的。使用dispatch_get_global_queue函数来获得一个合适的目标队列,具有所需的优先级。 如果您将块提交到串行队列,而串行队列的目标队列是不同的串行队列,则该块不会与提交到目标队列或具有相同目标队列的任何其他队列的块同时调用。"

        https://developer.apple.com/reference/dispatch/1452989-dispatch_set_target_queue

        1. .main 将在主线程上运行。主线程主要用于 UI 工作,因此在将此线程用于与 UI 无关的工作时应谨慎,因为它可能使 UI 挂起或显示无响应。此队列具有最高优先级。

        2. .global 主要用于与 UI 无关的其他工作。并在线程可用时安排块。全局队列具有三个优先级Low, Default & High。此队列具有 3 种不同类型的第二高优先级。

        3. nil 是最低优先级,将低于任何全局队列。它没有优先级,它只需要完成。

        总结

        .main 作为 UI 工作的目标

        .global 作为其他需要尽快完成的工作的目标

        nil 作为只需要在某个时间完成的工作的目标(你什么时候不打扰)

        【讨论】:

        • 这仍然令人困惑。对象将调用的“终结器”是什么?又和Qos有什么关系?
        • 每个队列都有自己的优先级,正如我在回答中解释的那样。 Qos 的意思是“服务质量”,允许您对队列中的各个工作进行分类。通过使用 Qos 描述工作,您可以确保它是节能的,并在队列中设置子优先级。因此,假设您有两个在主线程上执行的 UI 工作。您可以通过指定 Qos 来声明 work1 的优先级高于 work2。
        猜你喜欢
        • 2018-09-18
        • 2019-09-22
        • 2021-04-28
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多