7

I would like to perform some code synchronously in the background, I really thought this is the way to go:

let queue = DispatchQueue.global(qos: .default)
queue.async {
    print("\(Thread.isMainThread)")
}

but this prints true unless I use queue.async. async isn't possible as then the code will be executed in parallel. How can I achieve running multiple blocks synchronously in the background?

What I would like to achieve: synchronize events in my app with the devices calendar, which happens in the background. The method which does this can be called from different places multiple times so I would like to keep this in order and in the background.

swalkner
  • 16,679
  • 31
  • 123
  • 210
  • Why would you use `queue.sync` from the main thread? That will block the main thread until the code on the background thread completes. That completely negates the point of using a background thread. – rmaddy Jun 27 '17 at 06:27
  • why is it the main thread? It's `DispatchQueue.global` which I would expect to handle it in the background – swalkner Jun 27 '17 at 06:37
  • Can you tell us more about the usecase, _why_ you want to do this? – shallowThought Jun 27 '17 at 06:44
  • i am not sure i completely understand but perhaps you want to execute things in the background and in the correct sequence. If that is the case you could use a serial queue that maintains the order. Check answer here for more information https://stackoverflow.com/questions/19179358/concurrent-vs-serial-queues-in-gcd/35810608#35810608 – Abhineet Prasad Jun 27 '17 at 07:17

2 Answers2

5

Async execution isn't your problem, since you only care about the order of execution of your code blocks relative to each other but not relative to the main thread. You shouldn't block the main thread, which is in fact DispatchQueue.main and not DispatchQueue.global.

What you should do is execute your code on a serial queue asynchronously, so you don't block the main thread, but you still ensure that your code blocks execute sequentially.

You can achieve this using the following piece of code:

let serialQueue = DispatchQueue(label: "serialQueue")
serialQueue.async{  //call this whenever you need to add a new work item to your queue
    //call function here
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
2

DispatchQueue is not equal to a Thread. Think of it as of a kind of abstraction over the thread pool.

That being said, main queue is indeed "fixed" on the main thread. And that is why, when you synchronously dispatch a work item from the main queue, you are still on the main thread.

To actually execute sync code in the background, you have to already be in the background:

    DispatchQueue.global().async {
        DispatchQueue.global().sync {
            print("\(Thread.isMainThread)")
        }
    }

This will print false.

Also, as user @rmaddy correctly pointed out in comments, doing any expensive tasks synchronously from the main queue might result in your program becoming unresponsive, since the main thread is responsible for the UI updates.

user3581248
  • 964
  • 10
  • 22
  • There is no point having `DispatchQueue.global().sync`, I don't this is a good answer. – Ben Butterworth Jan 18 '21 at 18:07
  • Yes, please check your understanding of async's parameter, [DispatchWorkItem](https://developer.apple.com/documentation/dispatch/dispatchworkitem). Why would a WorkItem run asynchronous wrt. to each other OR lines of code inside the WorkItem be asynchronous? There is no need for `.sync`, and it also does nothing. The dispatch queue is a *queue* (FIFO). – Ben Butterworth Jan 20 '21 at 13:58
  • There's a difference between adding stuff to serial queue and executing code synchronously, which is what the OP wanted to achieve. – user3581248 Jan 20 '21 at 15:14
  • Your code doesn't achieve that (synchronous execution), and also that is impossible. The OP did not understand his real problem. David and I can read between the lines to see asynchronous is not the problem they're looking to solve: `Async execution isn't your problem` and `still ensure that your code blocks execute sequentially.` – Ben Butterworth Jan 20 '21 at 15:21
  • I think you misunderstand both `async` and `sync`. Using them both nested like this is completely useless. If you understand what sync does, you'll know it simply will return once complete (you expect it to somehow organize with another call to `sync` to make sure it runs, as you say "synchronously", **it won't**). Read this https://developer.apple.com/documentation/dispatch/dispatchqueue/2016083-sync – Ben Butterworth Jan 20 '21 at 15:31
  • ... I was just giving a simplified example of what he has to do in order to achieve what he wants, obviously using it EXACTLY like this makes no sense. Read my full answer, not only the part with the code snippet. – user3581248 Jan 20 '21 at 15:53
  • You still don't understand, what you're doing is writing extra code that does absolutely nothing. If you can maybe explain what you think its doing, it would help. Your existing answer is just wrong, and I cannot see how it is useful in any way (even if you added more code, or used it in multiple places). – Ben Butterworth Jan 20 '21 at 16:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/227610/discussion-between-user3581248-and-ben-butterworth). – user3581248 Jan 20 '21 at 17:13