Search code examples
swiftxcodegrand-central-dispatch

iOS GCD Sync and Async


I'm trying to figure out how sync and async methods work in GCD, but I made some test and don't really understand the result. This is a code from Playground

PlaygroundPage.current.needsIndefiniteExecution = true

let queueA = DispatchQueue(label: "my-awesome-queue")
let queueB = DispatchQueue(label: "one-more-awesome-queue", attributes: .concurrent)

for _ in 0...5 {
    queueA.sync {
        Thread.sleep(forTimeInterval: 0.2)
        print("😁")
    }
}

for _ in 0...5 {
    queueB.async {
        Thread.sleep(forTimeInterval: 0.2)
        print("😡")
    }
}

And result is

😁
😁
😁
😁
😁
😁
😡
😡
😡
😡
😡
😡

I don't really understand, why queueA blocks async tasks from other queue (queueB)? I thought different queues could be executed from different threads, and there are no problems to run sync queue and different async queue simultaneously. Or custom sync queues block any other queues (even main queue)?


Solution

  • Basically using sync from the main thread is always wrong, because now you are blocking the main thread. And that is exactly what you are doing! Only a background thread should sync onto another thread.

    and there are no problems to run sync queue and different async queue simultaneously

    Yes, there are. Nothing can happen "simultaneously". Everything has to "take turns".

    Or custom sync queues block any other queues (even main queue)?

    Yes. While Queue A is being called with sync and is sleeping, the calling thread (which in your code is the main thread) is blocked. You are not allowing things to "take turns". We cannot proceed to the Queue B calls because we are stuck in the Queue A calls.

    You will also notice that the Queue B results arrive much faster than the Queue A results did. That is because Queue B is being called with async and is concurrent, so the whole second loop, when it runs, runs immediately, doing all the loops, and so all the results arrive together. This is even more obvious if you print Date().timeIntervalSince1970 together with your output.