Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

In Swift, why is a custom serial queue with a global queue as its target not executed concurrently?

This is my first question here, so please be nice.
I struggle to understand the dynamics around a queue’s target in Swift:

  1. I have read that a custom queue inherits the behaviour of its target queue.

  2. In the example below, concurrentQueue has its attribute set to .concurrent.

    MEDevel.com: Open-source for Healthcare and Education

    Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

    Visit Medevel

  3. But because its target queue is DispatchQueue.main, which is serial by definition, concurrentQueue is getting executed serially:

    let concurrentQueue = DispatchQueue(label: "concurrentQueue",
                                        attributes: .concurrent,
                                        target: DispatchQueue.main)
    
    concurrentQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    
    concurrentQueue.async {
        for i in 6...10 {
            print(i)
        }
    }
    

    Output:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
  4. Conversely, if I have a custom serial queue which has a global queue as its target, which is concurrent by definition, I would my custom serial queue expect to get executed concurrently.

  5. However, my custom serial queue is still getting executed serially. Why is that?

PROBLEM STATEMENT:

  1. Here, serialQueue has not attribute defined which makes it a serial queue.

  2. Because it has a concurrent queue DispatchQueue.global(qos: .background) as its target, I would expect it to get executed concurrently.

  3. However, the output is still serial.

    let serialQueue = DispatchQueue(label: "serialQueue", target: DispatchQueue.global(qos: .background))
    
    serialQueue.async {
        for i in 1...5 {
            print(i)
        }
    }
    
    serialQueue.async {
        for i in 6...10 {
            print(i)
        }
    }
    

    Output:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    

>Solution :

The behavior you describe is correct.

  • If you create a private serial queue, regardless of its target, it will perform the tasks serially. The concurrent nature of the target queue does not affect the serial nature of your private queue.

  • If you create a private concurrent queue, if the target is serial, your private queue will be constrained to serial behavior of the underlying target queue.


This begs the question of what is the purpose of a target queue.

A good example would be an “exclusion queue”. See WWDC 2017 video Modernizing Grand Central Dispatch Usage. The idea is that you might have two separate serial queues, but you want them to run exclusively of each other, so you would create yet another serial queue, and use that as the target for the other two. It avoids unnecessary context switches, ensures serial behaviors across multiple queues, etc. See that video for more information.


Loosely related, see the setTarget(_:) documentation, which offers a little context for targets:

The target queue defines where blocks run, but it doesn’t change the semantics of the current queue. Blocks submitted to a serial queue still execute serially, even if the underlying target queue is concurrent. In addition, you can’t create concurrency where none exists. If a queue and its target queue are both serial, submitting blocks to both queues doesn’t cause those blocks to run concurrently. The blocks still run serially in the order the target queue receives them.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading