iOS Concurrency with GCD and Operations - Part 2: | Ray Wenderlich

hi Daiwen: sync blocks the current thread while the task runs on mySerialQueue. So, in this example, the value statement doesn’t run until changeValue() has finished.

In the async version, the value statement runs immediately, so shows the old value.

hi Audrey, thank for your tutorial.
I can not find different sync - serial and sync - concurrent.
I see it works the same.

there’s a nice example at ios - DispatchQueue Sync Concurrent - Stack Overflow

when you dispatch sync to a concurrent queue from two loops, the results can appear in a different order on each run, because the concurrent queue can run more than one task at a time, and you get a race condition

when you dispatch sync to a serial queue from the two loops, the results appear in alternate order each time, because the tasks run in exactly the same order they get added to the serial queue

the usleep(100) seems to favour the second loop: the runner1 result always appears first; if I comment out the sleeps, the runner0 result appears first.

2 Likes

Hi Audrey, great tutorial! Very clear and concise. I finished the whole course and reorganized my own knowledge and code ever used at work.

My other previous co-workers ever used DispatchSemaphore, is it old Objective-C thread safe tools, or part of GCD? Can I use serial queue to replace semaphore in the project? Thanks!

hi Mike! DispatchSemaphore is part of GCD, and is still useful.

Soroush Khanlou’s GCD Handbook shows a couple of uses.

However, Rob’s stack overflow answer advises against over-use of dispatch semaphores:

while the dispatch semaphore technique is a wonderful technique when absolutely needed, I must confess that I see too many new developers, unfamiliar with good asynchronous programming patterns, gravitate too quickly to semaphores as a general mechanism for making asynchronous routines behave synchronously.

And WWDC 2015 and 2016 GCD talks have pointed out that Apple’s priority inversion fix (promoting lower priority tasks) doesn’t work with dispatch semaphores, because they don’t have an owning task, so the system can’t tell where they’re being triggered.

Earlier in the WWDC 2015 talk, they discuss the use of serial queues as locks. Serial queues can take advantage of the priority inversion fix, so if that’s a factor in your project, you should try to use a serial queue. OTOH if it’s not broken 
 ;]

1 Like

Hi Audrey,

Thanks! So I will try getting more familiar with GCD basic knowledge first.

Hi Audrey,

One more question. In a project for the code not related to UI and I don’t assign a global queue to execute it, will the system assign a global queue or main queue automatically? For example, in viewDidLoad(), I call a method to get data from a third-party API by using URLSession and I don’t assign a global queue. Will the system execute it on a global queue or main queue? ( I understand after getting the data, in the completion handler I use main queue to update UI.)

Have a great weekend!

hi Mike,

a URLSession is an operation queue, so runs everything off the main queue — that’s why you have to dispatch UI updates to the main queue when the task finishes or while the task is running.

you could watch my URLSession video course next ;]

1 Like

Hi Audrey,

Got it, thanks. I will watch your URLSession video course next.

So if the func in the previous question is not downloading data via URLSession, let’s say a func (called func A) to calculate some numbers and return an Int. If I execute this func A in viewDidLoad and don’t assign a queue, the system will use a global queue or main queue?

If I want some task to run on a global queue, I must assign one global queue otherwise the system will run on main queue by default? (Except the scenario like URLSession, already runs off the main queue)

Thanks for your time.

1 Like

most things run on the main queue unless you dispatch them to another queue or add an operation to an operation queue

there are some APIs that run asynchronously, like URLSession and animations — when you look up examples or documentation, they usually advise you to run UI updates on the main queue.

In the URLSession course, I kept some UI code off the main queue, to demonstrate Xcode 9’s new main thread checker (edit scheme > Run > Diagnostics), which is very good at telling you which code must run on the main queue ;]

1 Like

Thanks Audrey, now I have a clear big picture. Will start learning your URLSession course shortly.

1 Like

Hi Audrey,

in video 2 where you describe the different cases of the qos enum, I dont understand the .userInteractive. You say everything that belongs to holding the UI responsive(like refreshing, updating
) shall be added to this concurrent queue. But I thought tasks updating the UI have to be performed on the main queue? Can you explain this in more detail?

Thanks !

1 Like

@audrey Can you please help with this when you get a chance? Thank you - much appreciated! :]

hi tamaril: I took those descriptions from Apple’s Energy Efficiency Guide for iOS Apps, and it’s true their description of .userinteractive includes “operating on the main thread, refreshing the user interface” but the 3rd example is animations, which don’t run on the main queue.

I think it’s because these quality of service levels are also used for Operations in OperationQueues, where the system takes over control of where to dispatch tasks. So specifying UserInteractive bumps up the priority to “do immediately”.

Hey @audrey
So a serial queue can’t perform tasks simultaneously, so it’s equivalent to sync tasks
Did I understand correctly?

hi Mansi: serial/concurrent aren’t equivalent to sync/async. You dispatch tasks from one queue to another queue. Serial/concurrent is about what happens on the destination queue: tasks run serially or concurrently.
Sync/async is about what happens on the source thread: the thread blocks or doesn’t block while the task runs on the destination queue. If the source queue is serial, there’s only one thread, so a serial queue blocks if you dispatch synchronously from it.

2 Likes

Oh Okay, Thanks :grin:

1 Like

Another great tutorial ! I’ll admit the Introduction Video was a bit long for an introduction but part 2 is good. I wish the web page video player had a back 10 seconds button on it. I find myself fumbling about as I rewind the video to catch a missed point.

At 20:25 your comment about dispatching a block of code synchronously to main serial queue from the main thread as a deadlock seems like an easy mistake to make. Good tip

Your quick example running a sync block of code on concurrent queue probably should be prefaced that it makes little sense to do this. Is that not correct ? All it does is run the code block from the calling thread when the queued message is finally extracted.

The example showing how to make a variable access synchronized is nice to know. It looks like the Swift team could have made a convenience wrapper word “synchronized” in the variable declaration as a less verbose way of doing this.

hi Art: thanks!

I hesitate to say “no one would do this” unless it’s something you mustn’t do — concurrency is such a strange beast!

And there are persistent rumours that a complete overhaul of how Swift handles concurrency is “coming soon” ;]

I’m a bit confused,

It doesn’t matter whether you run a task Synchronously or Asynchronously on a concurrent queue? Because it will just create a new thread for the new task anyway?

Also, it doesn’t matter whether you run a task Synchronously or Asynchronously on a serial queue either? Because it has to wait for the task to complete before starting a new one?