7 ms·
If concurrency is easy, you're either absurdly smart or you're kidding yourself
- noss 17y agoThis is a whole lot of text to describe determinism and non-determinism.
- gdp 17y agoUsing "determinism" with respect to concurrency means about a billion different things depending on who you talk to. For example, is the process that results from parallel composition of two deterministic processes deterministic or non-deterministic? The answer is "it depends". Concurrent "deterministic" processes are not significantly easier to reason about (informally) than non-deterministic ones, whichever definition you choose. In fact, re-reading, I definitely don't see anything in there that could described by either "determinism" or "non-determinism", so either your definition differs wildly from mine, or you're choosing to be dismissive deliberately :)
- fhars 17y agoUnix pipes (deterministic concurrrency) are far easier to reson about than a mutitheaded shared state program (nondeterministic concurrency). But then you can of course argue that this is due to the fact that the shell with proper unix filters form a monad with cat as the unit and the pipe operation | as bind.
- kevingadd 17y ago"It's our total inability to mentally reason about concurrency that makes it difficult"... hyperbole much? Ugh. Less ranting and more solutions, please? :)
- gdp 17y agoDuly noted, thanks!
- ori_b 17y agoFunnily enough, Plan 9 uses concurrency (via CSP) as a way of structuring programs to make them easier to write and reason about. Concurrency isn't hard; Sharing is hard. This is the reason that mutable state hurts understandability - things can change under you because the view of state is shared. This is the reason global variables are bad - they are shared between different parts of the program, and can be modified from places you can't see. And this is the reason shared-memory concurrency is hard. Add to shared-memory concurrency a dash of race conditions in operations involving a load and a store, and things get hard. Of course, I'm oversimplifying as I write this, but I think that's really the gist of it.
- gdp 17y agoI think I agree with most of that. I'm definitely a big fan of CSP, and some of its ideological successors. To this day I think that Occam is one of the most ingeniously elegant languages ever invented. I also think that making a distinction between concurrency and sharing is rather artificial. Embarrassingly parallel problems aside (where the concurrency is really better characterised as co-habitation of a computing resource), it's still pretty easy to get both shared-memory and channel-based message-passing wrong in concurrent situations. I agree that the presence of shared-memory makes it worse, and while my experiences using things like CML without using mutable storage have been much more positive than say... Java concurrency primitives, I think it's still "hard" in that it requires considerably more intellectual effort than writing non-concurrent programs of similar scope and size.
- cduan 17y agoThis is why I generally prefer event-driven programming over multithread programming. This is the sort of programming you do, for example, when you are implementing a GUI: you write short event handler functions that respond to events (such as mouse clicks or the completion of network or disk reads), and then a master loop receives events and dispatches the handler functions. You get the same benefits as concurrency (maximum processor usage, at least when you only have one processor), but you avoid the pitfalls of shared memory, race conditions, and unexpected state changes (because only one event handler runs at a time). It does take a bit of getting used to (it seems so easy to make function calls like time() or mkdir() that are actually blocking and thus technically should be separated into a new callback function). But I find that the benefits of processor efficiency plus the comfort of avoiding concurrency problems are worthwhile. http://en.wikipedia.org/wiki/Event-driven_programming http://en.wikipedia.org/wiki/Event-driven_programming
- swannodette 17y agoLearn Clojure. Learn Haskell. Learn Erlang. Learn Mozart Oz. And you'll suprised that you don't need to be a rocket scientist to write robust highly concurrent code.
- gdp 17y agosigh From the article: Now, before you jump up and down and tell me that "insert-your-favourite-concurrency-model-here addresses these problems", I know there are strategies for managing the complexity of these tasks. I did concurrency theory for a living, so I know some approaches are better than others. My point here was essentially to illustrate why it is important to manage complexity when doing concurrency. It's definitely not just a case of "you can't do concurrency so that means you are stupid". I'm arguing that pretty much everyone is bad at concurrency beyond some simple patterns of interaction that we cling to because we can maintain a good mental model by using them. To elaborate, things like the technologies you mentioned may provide better mental models for concurrent development, but I'm not convinced that they have solved concurrency in its entirety.
- swannodette 17y agoI noted that from the article. But nowhere did you mention how these languages fail to allow for complex concurrent modeling, which they do. You simply discussed your viewpoint without context for how these languages do not competently allow for massively concurrent programs- that's what they're designed to do. And I'm not saying they solve "concurrency in it's entirety". I'm not even clear what you're trying to express with that statement.
- gdp 17y agoLet me clarify: I'm a big fan of most of the languages you've described. I think they do a really good job in the problem domains they are designed for. My only point is that the domains they are designed for are constrained. I don't mean this as a negative - I consider a general pthreads-style implementation of concurrency to be constrained by the ability of people to reason about that kind of concurrency, probably to a much larger degree than a considerably more elegant implementation in a modern functional programming language. I would argue, however, that such languages simply make it easier to construct concurrent programs that follow certain patterns. They provide useful abstractions for managing the complexity of concurrent interactions, which I think was my original point, and which I think is brilliant! What is missing is something that provides good-quality abstractions, high-quality static analysis and very strong safety guarantees in the general case. Think about things like mobile processes, "ubiquitous computing" and software with huge failure tolerances by virtue of being able to reconfigure and coalesce resources at will. And hopefully the flow-on effect of that would be to essentially stop horrible concurrency implementations being used in languages like Java and friends.
- dkarl 17y agoIt takes him all of five sentences to back off from his sensationalistic headline and admit there is another possibility: or the way they are using concurrency is restricted to nice simple patterns of interaction to which we can apply some simple mental analogy Actually this possibility covers most programming requirements. I like to think I'm superhumanly smart, and I would love to tackle a hard concurrency problem, but so far I have only needed mundane engineering ingenuity to map my problems to known solutions.
- gdp 17y agoI see. The post was essentially a reaction against people going "concurrency is easy! What are you talking about it being hard?!" When people say "concurrency is easy", they mean "I use little bits of concurrency that I understand well and I find those easy". That's not the same as "concurrency is easy". That kind of arrogance is essentially like saying "flying a jet fighter is easy, because I know how to use a seatbelt".
- brg 17y agoIn an ideal world, concurrency need not be a problem. After all, we can say that it is simply a matter of checking the safety of every read/write against every possible state of every thread that may be running concurrently. However, the reality is that developers can not do this checking with complete accuracy. The simplistic reason is that the complexity of concurrent programs is exponentially greater than that of non-concurrent programs. In a concurrent model if I have m threads of execution and n read/writes per thread I need to verify n^m states in my code. Such a blowup in state makes any reasonable person look for generalizations and optimizations, but those then lead incorrect assumptions and ultimately defects. Outside of this simplistic reasoning lie other problems which serve to exacerbate code verification during design and construction; realities of deadlines, access to source or documentation of components, the learning curve of technologies used as black boxes.