3

when should we use semaphore vs Dispatch group vs operation queue ?

what i understood is:

Use semaphore : when multiple threads want to access shared resource.

Use Dispatch Group: when you want , you should be notified after all threads (which are added to dispatch group) finishes their execution.

Use Operation Queue: when you want that operation C should start after A and B finishes their execution. So A and B has a dependency over C.

is my understanding correct or not ?

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Matrix
  • 7,477
  • 14
  • 66
  • 97
  • 1
    [this](https://stackoverflow.com/questions/46169519/mutex-alternatives-in-swift/46174300#46174300) will give you some idea. – beshio Nov 25 '19 at 10:57

1 Answers1

9

I’m gathering you’re focusing on these three techniques’ ability to manage dependencies between units of work. Bottom line, semaphores are a low-level tool, dispatch groups represent a higher level of abstraction, and operation queues are even more high-level.

A few observations:

  • As a general rule, semaphores are a low-level tool that should be used sparingly as they are easily misused (e.g., easy to accidentally cause deadlocks, easy to block the main thread, even when used properly they unnecessarily block a thread which is inefficient, etc.). There are almost always better, higher-level tools.

    For example, when doing synchronization, locks and GCD queues generally not only offer higher-level interfaces, but are also more efficient, too.

  • Dispatch groups are a slightly higher level tool, and a great way of notifying you when a series of GCD dispatched blocks of code are done. So, if you’re already using GCD, dispatch groups are a logical solution.

    Note, I’d advise avoiding the wait function (whether the semaphore or the dispatch group rendition). Use dispatch group notify method instead. Using notify, you mitigate deadlock risks, avoid unnecessarily tying up threads, avoid risking blocking the main thread, etc. The dispatch group’s wait function only re-introduces some of the same potential semaphore problems. But it’s hard(er) to go wrong when using notify.

  • Operation queues are an even higher-level tool. Yes, you can manage dependencies as you outlined, but you can also do more general “run series of asynchronous operations sequentially” or “run series of asynchronous operations, but not more than x operations at a time”. It’s a great way of managing series of asynchronous tasks.

    But operations are more than just a way of managing a series of asynchronous units of work. The other benefit is that it provides an established framework to wrap a unit of work in a discrete object. This can help us achieve a better separation of responsibilities within our code. So you can have queue for network operations, queue for image processing operations, etc., and avoid scenarios, for example, where we bury all of this code in our view controllers (lol).

So, as a gross over-simplification, I’d suggest:

  • avoiding semaphores altogether;
  • using dispatch groups with notify pattern if you want to be notified when a bunch of dispatched blocks of code are done; and
  • considering operation queues if you want to abstract complicated asynchronous code into distinct objects or have more complicated dependencies/concurrency scenarios with asynchronous tasks.

All of that having been said, nowadays, the Swift concurrency system (a.k.a., async-await) obviates most of the above patterns, allowing one to write elegant, readable code that captures asynchronous processes.

Rob
  • 415,655
  • 72
  • 787
  • 1,044