Search code examples
swiftgrand-central-dispatchdispatchdispatch-queue

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

If the global queue is not stored in a variable, the order of A, B, C, D is different each time.
When the global queue is stored in a variable, A, B, C, and D are called in sequence always(*in a playground).

I wonder why the code execution results above and below are different.
Are there multiple global queues?


Solution

  • Other answers have discussed the order in which blocks are executed, but I want to directly address your question: “Does DispatchQueue.global().async make a new global queue?”

    It does not.

    We can check empirically by printing the ObjectIdentifier of the queue:

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

    It prints the same ObjectIdentifier twice, so both calls to DispatchQueue.global() return the same object.

    We can also answer the question by looking at the source code. DispatchQueue.global() is a Swift wrapper for the C function dispatch_get_global_queue. The source is 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);
    }
    

    It calls _dispatch_get_root_queue. The source for that is 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];
    }
    

    It's just an array lookup, so it returns the same value every time, unless the contents of _dispatch_root_queues changes—which it doesn't.