Concurrency's shysters
dtrace.org
dtrace.org
'“Locks are not modular and do not compose, and the association between locks and data is established mostly by convention.” Again, no data, no qualifiers, no study, no rationale, no evidence of experience trying to develop such systems...'
It is well known that lock based concurrent libraries do not compose, and anyone writing articles about concurrency should not require an explanation of this central issue in the discussion[1]. Of course with millions of hours of developer investment in a centrally managed codebase like Solaris it is possible to achieve incredible parallelism with locks, but that isn't practical for the vast majority of modern software, which continues to use ever more external libraries.
Clojure's STM paired with immutable data structures are an especially well suited combination that are unlike most of the research systems presented in this area. Of course there are additional resources that will have to be managed, such as access to I/O, but I would argue that access to I/O is by far the easier problem to deal with in comparison to concurrent access to memory - primarily because I/O devices are typically accessed serially so you can just queue up requests.
[1]: Here's one explanation with a code example of why locks don't compose: http://www.drdobbs.com/article/printableArticle.jhtml;jsessi...
But take Clojure, which AFAIK is the only real system people are actually using that places STM front and center (except maybe something in Haskell land). Rich Hickey is the furthest thing possible from a shyster.
For example, he never claimed that STM is faster than manual locks, just that it's an order of magnitude easier to write correct programs - which seems to be borne out in actual experience. Yes, there's a not-insignificant overhead. But for most programs it's still probably worth it.
Similarly, the claim that STM isn't any good because most computational resources aren't memory is a complete red herring - STM is quite useful for memory management, and for other resources, well, find a different strategy. It doesn't stop STM from being quite useful in its domain.
All in all, this sounds more of a luddite rant than a reasoned opinion. It reminds me of what I've read of the initial objections to managed memory or even high-level languages themselves. Of course a lot of the technology isn't there yet. Of course a lot of it is going to be rabbit trails that ultimately don't deliver. It still doesn't mean it's not the future.
If you agree that many resources that require serial access are not memory then I also don't see how STM is making your life significantly easier. Composing locks and transactions in the same system sounds much harder to me than just using locks.
I think the jury is still out on the effectiveness of Clojure's concurrency model. It makes for nice short examples but I'm not aware of anything of any real complexity built on it yet.
All I mean to say is, some of those fancy new technologies do grow up to become quite useful.
And STM is designed around memory access. If you're attempting to write a concurrent program, and you have heterogeneous resource types, shouldn't you use a strategy which is optimal for each one? An IO socket is a fundamentally different sort of thing than memory, and ought to be managed differently.
You'll have to admit it's extremely thin on actual arguments. There are lots of links to journal publications, but it would have helped to summarise their actual findings rather than hand-wave about "complexity".
Composing locks and transactions in the same system sounds much harder to me than just using locks. I think the jury is still out on the effectiveness of Clojure's concurrency model.
Actually, Clojure does address that by allowing you to compose transactions with agents. If you send messages to agents during a transaction, they will only receive the messages sent from the transaction attempt that successfully completed. This leads to a fairly natural state-change-then-I/O pattern where the agent locks the non-memory resource and operates on it.
It's a blog post. What do you expect? The ACM article he links to is excellent, with some very in-depth analysis and real benchmark numbers showing exactly where the overhead of STM is most onerous.
More importantly, Clojure is wisely designed with several other equally useful concurrency mechanisms: atoms for serial access, promises for dataflow, pmap for divide and conquer, and agents for uncoordinated concurrent activities.
For example, I'd like to see if a Clojure solution of the benchmarks in the linked ACM paper can scale better than the solutions tested in the paper.
For example http://dosync.posterous.com/stm-couchdb-and-pushing-5500-doc.... I added only 7 lines of code. Raw Aleph runs at about 20k req/s on an 8 core box. This code performs at about 14-18k req/s. So clearly some contention is at play. I could write this with locks, but I have better ways to spend my time. That's the real cost-to-benefit ratio.
http://blog.ezyang.com/2010/07/graphs-not-grids/
http://www.bluebytesoftware.com/blog/2010/07/12/ThoughtsOnIm...
[1] Parallelism = speeding things up by using multiple cores. Concurrency = modelling a system that naturally has different activities going on at once. These are not the same thing.
http://stackoverflow.com/questions/1996524/optimizing-perfor...
http://www.erlang-factory.com/conference/London2009/speakers...
n-body without SMP 123.30s
n-body without SMP 123.30s elapsed
n-body with SMP 133.52s
n-body with SMP 133.57s elapsed
spectral-norm without SMP 46.68s
spectral-norm without SMP 46.68s elapsed
spectral-norm with SMP 47.71s
spectral-norm with SMP 13.90s elapsed
mandelbrot without SMP 230.07s
mandelbrot without SMP 230.10s elapsed
mandelbrot with SMP 253.66s
mandelbrot with SMP 87.76s elapsed
Maybe that Erlang chameneos-redux program is unusual?
Exactly. This is the core problem with threading in real systems. Not that it's not possible, but it's not likely going to yield good results with your non-kernel devs. And unfortunately, given that processors are now getting most of the perf benefit by adding cores, this is a problem.
And his conclusions about two-level scheduling, IMO, should be tempered. For example, the lack of pre-emptability is something that I believe most user-level thread packages now deal with. Another issue he discusses is that under load, the kernel doesn't realize that there are 'm' degrees of parallelism. It only sees the LWP. But a good user-level threads package should work system-wide.
He also says that detachment and reattachment is more expensive than one might think. I'm curious if they looked at some of their contemporary work, like Cilk, to see how they handled this?
I actually think he did good work in his thesis. But it seems more like a snapshot of a particular implementation than a statement about the technology in general.
- Separating a cold thread from its underlying hot thread is not without performance overhead...
Of course cache misses dominate performance. This is basically the first vector that work stealing queues attack. For eg. erlang tries to tie erlang processes to the same run queue (which maps to a kernel thread), for as long as it can as long as it maintains reasonably balanced run queues.
- Lack of preemptibility based on time quanta creates performance problems...
Well yeah, but either that is part of the model already (thread pool), or that is taken into account by the user level scheduler (ie. run X instructions or time then automatically yield to next runnable user level process).
- Nondeterministic LWP creation can have an appreciable and unpredictable impact on performance. The nondeterministic nature of the SIGWAITING mechanism makes performance debugging difficult...
Mainly because the SIGWAITING mechanism hes described (which sounds like it is based on solaris) is pretty bad for implementing user level scheduling. Windows 7 and MAC OS X Snow Leopard both seem to do significantly better (Maybe that's because they've had 10+ years to fix it...). In any case thread pools have generally worked around this by handling LWP creation based on the number of waiting threads and have seemed to be reasonable in performance.
That he even brings up his 14 year old outdated thesis is pretty sad when talking about the state of the art today. STM is no panacea but it is not worthless either.