I’ve been doing some research on the various approaches to concurrency, and I’ve ended up with the following taxonomy:

  • Manual thread based concurrency with locks
  • Asynchronous dispatch queues and callbacks as implemented in Apple’s libdispatch (GCD)
  • Asynchronous functions, blocking, and message passing as first class language constructs as implemented in Go
  • Functional concurrency where immutability makes parallelization near automatic as implemented in Haskell, Clojure, etc.

Obviously this isn’t a ‘pure’ taxonomy (since some elements are built on top of others), but it seems to correspond with the paradigms that people and languages adopt for writing real, useful code (i.e. not academic papers).

Assuming that my list is correct, I’m looking for a grizzled concurrency veteran to give me brief rundown on the pros and cons of each.

For example, most people tend to view threads as hard to manage, but appreciate that they’re a low level construct which can be highly performant if you can afford the dev time. I’m looking for that level of detail on the other 3, and any relevant comparisons between them.

  • 1
    recommended reading: What is the problem with “Pros and Cons”?
    – gnat
    Nov 23, 2015 at 20:50
  • I actually did some research on meta, and really tried to avoid the pitfalls of bad pros and cons questions when writing this one
    – ebrts
    Nov 23, 2015 at 20:52
  • 4
    This question seems a bit broad. Questions are too broad if a good answer could fill the better part of a book chapter... (or perhaps even a whole book in this particular instance). Can you make your question more specific? It would help if we had some information about your specific use case. Nov 23, 2015 at 20:57
  • 1
    It's likely that your particular concurrency problem has certain characteristics that make just one of the approaches a best fit. Nov 23, 2015 at 21:00
  • 1
    I don't have much to add other than the fact that parallelism is not concurrency. The goal of "functional concurrency" as you call it is to improve efficiency without changing the semantics of the program. The overall behavior of the program is still deterministic and the scheduling involved can be cooperative. Regular concurrency is generally concerned with the interaction of two separate processes and is non-deterministic.
    – Doval
    Nov 23, 2015 at 21:30

1 Answer 1


The fact that some environments mix and match some approaches unnecessarily complicates the discussion, so it is best left out. Asynchronous functions are largely equivalent to message passing, (just a more convenient syntax,) so they do not need to be regarded as a separate category.

So, the four approaches that you listed can be restated as only three:

  • Synchronization with locks.
  • Message passing.
  • Functional concurrency.

Synchronization with locks tends to yield elegant designs that are expressed with a minimal number of lines of code. The problem is, they are very hard to debug, and it is impossible to guarantee their correctness, because they are not testable. Your program may contain a timing-related defect which only manifests itself once in a million operations, meaning that you stand virtually no chance of discovering it during in-house testing, but once you ship your product to millions of users all over the globe, who are exercising it around the clock, the defect starts manifesting itself somewhere on the planet every few minutes or so, and that's when your nightmare begins. Untestability means that no matter what you do, at the moment that you ship your product you cannot be sure that it will not result in such a nightmare.

Message passing tends to require more code, but it is easier to debug, and most importantly, it is testable. What this means is that once your system works, it can be expected to continue working without surprises. Of course, this requires some discipline, for example making sure that you never pass anything mutable in your messages, but with proper tools this is something that can be enforced and not left to chance.

As for functional concurrency, let's see if someone who has actual experience with it can tell us some of its pros and cons. One disadvantage that I know it has is that it is painful to debug, because it is difficult to set a breakpoint on a subexpression, or to single-step into a subexpression, though I would expect that this is a limitation of debuggers, and debuggers should really be getting better at this.

Not the answer you're looking for? Browse other questions tagged or ask your own question.