What is the default target queue for a serial queue?

didn't meant to sound rude or something in my previous post.

Please rest assured that I’m thoroughly enjoying every aspect of this thread!

Of course one should not everdo the usage of queues, to prevent things
alike thread explosion.

I think that’s the key point. There’s two different types of parallelism problems that you can solve with Dispatch, symmetric and asymmetric:

  • In symmetric parallelism you have a whole bunch of blocks that all need to do the same work. In that case I strongly favour dispatch_apply (aka DispatchQueue.concurrentPerform(iterations:execute:)) because it lets Dispatch decide on how best to map your work to available CPUs.

  • In asymmetric parallelism you have different subsystems within your program and you want them to be able to run on different CPUs. In that case the design I favour is a ‘forest’ of serial queue trees, connected via the target queue, where the root of each tree is a serial queue that provides the actual concurrency for the entire subsystem. This idea is explored in depth in WWDC 2017 Session 706 Modernizing Grand Central Dispatch Usage, which is a great resource.

Finally, I want to stress that Dispatch isn’t magic. To work efficiently you have to size the work done by your dispatch blocks appropriately. This matters most in the symmetric case, and that’s something specifically called out in the dispatch_apply man page (look for the text starting with “Sometimes, when the block passed to dispatch_apply is simple, the use of striding can tune performance.").

However, it can also be relevant in the asymmetric case. For low-level primitives within your program it’s often best to not implement any concurrency control, but instead require that the caller serialise calls to that primitive. That makes the primitive’s code easier and also encourages the caller to do more work in each dispatch block, which is generally more efficient.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

9 Likes