`DispatchQueue.global().async` 是否创建新的全局队列?

Does `DispatchQueue.global().async` make new global queue?

DispatchQueue.global().async {
    print("A")
}
DispatchQueue.global().async {
    print("B")
}
DispatchQueue.global().async {
    print("C")
}
DispatchQueue.global().async {
    print("D")
}

let a = DispatchQueue.global()

a.async {
    print("A")
}
a.async {
    print("B")
}
a.async {
    print("C")
}
a.async {
    print("D")
}

如果全局队列没有存储在变量中,每次A、B、C、D的顺序都不一样。
当全局队列存储在变量中时,总是按顺序调用 A、B、C 和 D(*在操场上)。

我想知道为什么上面和下面的代码执行结果不同。
是否有多个全局队列?

我运行你的代码并得到:

B
B
A
D
A
C
C
D

所以所有 8 个打印语句都相互交错,不完全是 运行domly,但也没有特定的模式。较早的打印语句往往会比较晚的打印语句早一点执行,但基本上它是不可预测的——它是异步的。

他们以正确的顺序打印可能只是巧合。 DispatchQueue.global() 的文档说。

Tasks submitted to the returned queue are scheduled concurrently with respect to one another. https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global#

因为它说它们是同时安排的(而不是连续安排的),所以不应期望它们总是以相同的顺序打印。

异步任务也没有真正做任何事情。我怀疑它们之间没有足够的可变性来导致打印不同的订单。

根据我在操场上看到的内存地址,

DispatchQueue.global() 看起来总是 returns 相同的实例。它可能在幕后做了一些额外的事情,可能会在每个异步任务的执行时间中引入一点可变性。

交换代码中两个测试的顺序也为我产生了不同的输出,确认不应依赖该顺序。

A2
C2
D2
B2
A1
B1
C1
D1
let a = DispatchQueue.global()

a.async {
    print("A2")
}
a.async {
    print("B2")
}
a.async {
    print("C2")
}
a.async {
    print("D2")
}

DispatchQueue.global().async {
    print("A1")
}
DispatchQueue.global().async {
    print("B1")
}
DispatchQueue.global().async {
    print("C1")
}
DispatchQueue.global().async {
    print("D1")
}

其他答案已经讨论了块的执行顺序,但我想直接回答你的问题:“DispatchQueue.global().async是否创建一个新的全局队列?”

没有。

我们可以通过打印队列的 ObjectIdentifier 来凭经验检查:

import Dispatch

let q = DispatchQueue.global()
print(ObjectIdentifier(DispatchQueue.global()))
print(ObjectIdentifier(q))

它打印相同的 ObjectIdentifier 两次,因此两次调用 DispatchQueue.global() return 相同的对象。

我们也可以通过查看源代码来回答问题。 DispatchQueue.global() 是 C 函数 dispatch_get_global_queue 的 Swift 包装器。来源是 here:

dispatch_queue_global_t
dispatch_get_global_queue(intptr_t priority, uintptr_t flags)
{
    dispatch_assert(countof(_dispatch_root_queues) ==
            DISPATCH_ROOT_QUEUE_COUNT);


    if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) {
        return DISPATCH_BAD_INPUT;
    }
    dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
#if !HAVE_PTHREAD_WORKQUEUE_QOS
    if (qos == QOS_CLASS_MAINTENANCE) {
        qos = DISPATCH_QOS_BACKGROUND;
    } else if (qos == QOS_CLASS_USER_INTERACTIVE) {
        qos = DISPATCH_QOS_USER_INITIATED;
    }
#endif
    if (qos == DISPATCH_QOS_UNSPECIFIED) {
        return DISPATCH_BAD_INPUT;
    }
    return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
}

它调用 _dispatch_get_root_queue。来源是 here:

DISPATCH_ALWAYS_INLINE DISPATCH_CONST
static inline dispatch_queue_global_t
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
    if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
        DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
    }
    return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}

这只是一个数组查找,所以它 return 每次都是相同的值,除非 _dispatch_root_queues 的内容发生变化——但事实并非如此。