I am interested in learning concurrent programming, focusing on the application/user level (not system programming). I am looking for a modern high level programming language that provides intuitive abstractions for writing concurrent applications. I want to focus on languages that increase productivity and hide the complexity of concurrent programming.

To give some examples, I don't consider a good option writing multithreaded code in C, C++, or Java because IMHO my productivity is reduced and their programming model is not intuitive. On the other hand, languages that increase productivity and offer more intuitive abstractions such as Python and the multiprocessing module, Erlang, Clojure, Scala, etc. would be good options.

What would you recommend based on your experience and why?

EDIT: Thanks everybody for your interesting answers. It's hard to make a conclusion without actually trying since there are many good candidates: Erlang, Clojure, Scala, Groovy, and perhaps Haskell. I voted the answer with the most convincing arguments, but I'll try all the good candidates before deciding which one to pick :)

This question appears to be off-topic. The users who voted to close gave this specific reason:

"Questions about what language, technology, or project one should take up next are off topic on Programmers, as they can only attract subjective opinions for answers. There are too many individual factors behind the question to create answers that will have lasting value. You may be able to get help in The Whiteboard, our chat room." – Thomas Owens

To give an example, I don't consider a good option writing multithreaded code in C, C++, or Java. Why? On the other hand, Python and the multiprocessing module, Erlang, Clojure, Scala, etc. are some of my options. Again, why? Expand your question to better define what you're actually looking for.
–
Yannis Rizos♦Nov 22 '11 at 18:17

2

So do you want to learn parallel programming with all the gotchas or you want to hide some of its complexity and focus on productivity?
–
MaRNov 22 '11 at 18:24

1

@DeadMG Decreased productivity is their problem. I don't want to focus on the syntax of the language instead of the problem. I definitely don't want to end up struggling with deadlocks. As a simple example, I want to use simple statements such as begin transactionend transaction and everything inside should be deadlock-free and either succeed or fail as a whole.
–
faifNov 23 '11 at 18:43

16 Answers
16

You almost certainly should look at Clojure - in my opinion it's the best modern language for multi-core programming and it is extremely productive.

Key attributes:

It's a functional language, which is a boon for both concurrency and your ability to develop using higher level abstractions. It features fully immutable persistent data structures and lazy sequences which will be familiar to anyone with experience in functional languages like Haskell.

It features a very novel software transactional memory system for concurrent lock-free access to mutable state. Making code concurrency-safe is often as simple as wrapping it in a (dosync....) block.

It's a Lisp - which makes it extremely powerful for macro-based metaprogramming and code generation. This can bring significant productivity advantages (essay by Paul Graham - "Beating The Averages")

It's a JVM language - so not only do you get access to the huge array of libraries and tools in the Java ecosystem, you also benefit from the huge engineering effort that has gone into making the JVM an effective platform for concurrent server-side applications. For practical purposes, this gives it a huge advantage over languages that don't have this kind of foundation to build upon.

It's dynamic - which results in very concise code and a lot of productivity. Note however that you can use optional static type hints for performance if needed.

The language is designed around abstractions which is somewhat hard to explain but the net effect is that you get a set of relatively orthogonal features that you can combine to solve your problems. An example would be the sequence abstraction, which enables you to write code that deals with every "sequential" type of object (which includes everything from lists, strings, Java arrays, infinite lazy sequences, lines being read from a file etc.)

There's a great community - helpful, insightful but most importantly very pragmatic - the focus in Clojure is generally on "getting things done".

Some mini code samples with a concurrency slant:

;; define and launch a future to execute do-something in another thread
(def a (future (do-something)))
;; wait for the future to finish and print its return value
(println @a)
;; call two functions protected in a single STM transaction
(dosync
(function-one)
(function-two))

The purpose of static type declarations in strongly-typed languages is not to "improve performance where needed," and I'm getting kind of sick of Lisp advocates trotting out that old strawman. Type declarations have two purposes: to provide certain compile-time guarantees of correctness, and to make the code easier to read, especially for someone other than the original author. The inherently better performance that static typing provides is just a bonus.
–
Mason WheelerNov 23 '11 at 17:44

6

I've had to work with another developer's JavaScript code lately at work, and that's the most painful part of the process: with no types on the function arguments, I have to hunt throughout the entire codebase to figure out what they're supposed to be and what they can do based on where they're called from. This would be a non-issue if JavaScript had retained C's type system in addition to its general syntax.
–
Mason WheelerNov 23 '11 at 17:45

1

@MasonWheeler: IMHO if you can't figure out how to call a function without type annotations, it's a problem with the documentation (or lack thereof). Even in duck typed languages everything usually has to satisfy some structural type constraints (e.g. must support arithmetic operations, must be iterable, must be indexable, etc.). Static types would only help minimally because they wouldn't give much hint about what the function does.
–
dsimchaNov 24 '11 at 0:50

1

@Mason I never said that there weren't other advantages to static type declarations. In fact I like static type declarations for exactly the reasons you state. However I also like the productivity gains of dynamic typing. It's a trade-off. If you have a good test suite, I generally find that this mitigates a lot of the downsides of dynamic typing both in terms of ensuring correctness and providing example code to help newcomers understand correct usage. YMMV.
–
mikeraNov 25 '11 at 11:40

1

@dsimcha - the alternative to designing around abstractions would be to design around a concrete implementation. For example, most of the old Lisp functions worked only on linked lists stored in cons cells. You needed different functions for different data structures. In Clojure, the core library function work on anything sequential (as in the answer).
–
mikeraNov 25 '11 at 11:43

Many personal computers and workstations have two or four cores (that is, CPUs) that enable multiple threads to be executed simultaneously. Computers in the near future are expected to have significantly more cores. To take advantage of the hardware of today and tomorrow, you can parallelize your code to distribute work across multiple processors. In the past, parallelization required low-level manipulation of threads and locks. Visual Studio 2010 and the .NET Framework 4 enhance support for parallel programming by providing a new runtime, new class library types, and new diagnostic tools. These features simplify parallel development so that you can write efficient, fine-grained, and scalable parallel code in a natural idiom without having to work directly with threads or the thread pool. The following illustration provides a high-level overview of the parallel programming architecture in the .NET Framework 4...

The Actor model in computer science is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent digital computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and determine how to respond to the next message received... It has been used both as a framework for a theoretical understanding of computation, and as the theoretical basis for several practical implementations of concurrent systems.

I think it depends on what it is you're building. Desktop apps, or server? I've heard that (but don't have personal experience) node.js great for concurrent programming for servers (both in terms of writing code and in performance). If I wanted to write a new server app, I'd probably try that out. Not sure about desktop apps... I've written a fair amount of stuff in C# and there are some tools that hide the complexity nicely, though for other cases you have to deal with it head-on.

Erlang is definitely a great option, but something a little more practical might be Go, Google's new language.

It's not so far from other common languages, so it's typically easy to get if you already know other 'easy' languages. Many people compare it with Python or even Lua in terms of how 'comfortable' is it to program.

@Chiron: Erlang is a programming language, it's used to create applications. Typically, multitprocessing applications. I don't know where does it fit as 'systems concurrent proramming', I haven't heard of any OS written in Erlang.
–
JavierNov 23 '11 at 13:56

1

After taking a quick look in the Go tutorial I want to say that IMHO a language with a C-like syntax which uses (limited) pointers is definitely not a modern language that increases productivity.
–
faifNov 23 '11 at 18:40

In the next version, C# makes it even easier than that diagram shows. There are two new keywords Async and Await.

Async is used as a function modifier and says "this operation performs its work on another thread.

Await is used within an Async function, and this is where the magic happens. Basically Await tells the compiler to run the operation following the keyword in a seperate thread and wait for the results. Any code after the await call runs after the operation.

ALSO, the operation synchronizes to the calling thread (so if you are doing an asynch operation in response to a button click, you don't have to manually post back to the UI thread). Two little keywords and you get a lot of concurrency power. Read more here

You may also want to look at Groovy and the GPars library. GPars BTW is somewhat similar to .NET Parallel Extension mentioned in another answer, but Groovys flexible syntax makes it read better in some circumstances.

You could try D. It offers three models. I recommend either the first or second.

std.concurrency. If you use this module for all your concurrency needs, then a combination of the language and the standard library enforces isolation between threads. Threads primarily communicate via message passing, with limited support for shared memory in a way that favors "safety first" and disallows low-level data races. Unfortunately the documentation of std.concurrency needs improvement, but the model is documented in a free chapter of Andrei Alexandrescu's book, "The D Programming Language".

core.thread is a low-level wrapper over OS-specific threading APIs. Both std.concurrency and std.parallelism use it under the hood, but I would only recommend using it if you're writing your own concurrency library or find some ridiculous corner case that can't be done well in either std.parallelism or std.concurrency. No one should use something this low-level for day-to-day work.

I'm learning about Haskell right now, and reading this paper has convinced me that Haskell is a good option for concurrent programming. Because it's purely functional (the type system knows whether a function does any input, output, or reading/modification of global state), it can do things like Software Transactional Memory (summed up very nicely in the above paper) which behaves similarly to transactions in databases - you get a bunch of nice things like atomicity with only a little extra sugar. AFAIK, Haskell threads are very light-weight too.
In addition to these things, the fact that Haskell is purely functional lets even simple tasks be run in parallel with little more than a single keyword (par). source

I'd still recommend C++. It is more than capable of the necessary abstractions to write decent concurrent code. The overwhelming probability is that you simply have a poor library for doing the job, since good libraries for doing the job are relatively new, and indeed, the knowledge for using C++ well is not exactly common. Intel's TBB has only been around for a few years, and Microsoft's PPL has only shipped since last year.

If you use something like TBB or PPL, then concurrent code is, well, not exactly trivial to write, insofar that concurrency is never trivial, but far from arduous. If you use pthreads or Win32 threads directly, then it's no wonder you don't like it- you're practically writing in assembler with such functions. But with the PPL, then you're talking about standard functional algorithms that are parallelised for you, generic data structures for concurrent access, and that sort of good stuff.

I would suggest Groovy/Java/GPars if you can be JVM based since it allows for actors, dataflow, communicating sequential processes (CSP), data parallelism, software transactional memory (STM), agents, ... The point here is that there are many high-level concurrency and parallelism models each of which has different "sweet spots". You do not want to use a model that is not in harmony with the solution to a problem you are trying to construct. Languages and frameworks with only one model coerce you into algorithm hacking.

Of course I might be seen as biased as I am contributor to Groovy and GPars. On the other hand I do work with CSP and Python, cf. Python-CSP.

A further point is that the original question is about learning, not about writing a production system. So the Groovy/Java/GPars combination is a good way of learning even if the eventual production work is done in C++ using something like Just::Thread Pro or TBB rather than being JVM based.

(Some perfectly reasonable URL links had to be removed because of some panic about spamming by the host site.)

Concurrent programming is a large topic and there is space only for some Go-specific highlights here.

Concurrent programming in many environments is made difficult by the subtleties required to implement correct access to shared variables. Go encourages a different approach in which shared values are passed around on channels and, in fact, never actively shared by separate threads of execution. Only one goroutine has access to the value at any given time. Data races cannot occur, by design. To encourage this way of thinking we have reduced it to a slogan:

Do not communicate by sharing memory; instead, share memory by communicating.

This approach can be taken too far. Reference counts may be best done by putting a mutex around an integer variable, for instance. But as a high-level approach, using channels to control access makes it easier to write clear, correct programs.

One way to think about this model is to consider a typical single-threaded program running on one CPU. It has no need for synchronization primitives. Now run another such instance; it too needs no synchronization. Now let those two communicate; if the communication is the synchronizer, there's still no need for other synchronization. Unix pipelines, for example, fit this model perfectly. Although Go's approach to concurrency originates in Hoare's Communicating Sequential Processes (CSP), it can also be seen as a type-safe generalization of Unix pipes...

A plug for Ada is needed here, as it has all the top level abstractions for parallelism & concurrency. otherwise known as tasking. Also as OP asked for intuitive (a subjective criteria!) i think a different approach to the java-centric world might be appreciated.

I may get hit over the head for this, but have you read chapter 7 of TAOUP? The section I'm thinking of specifically is threads vs processes. I've found that the concept of concurrent processing makes most people think of threads, yet I've never seen an instance where a thread is easier and faster to use than spawning a child process.

You are farming out all the details of handling concurrency to the smart guys who built your OS. There's already lots of communication methods in place, and you don't have to worry about locking of shared resources. Basically, threads are an efficiency hack, which falls under the rule of optimization. Don't optimize if you haven't tested for necessity.

Find a good subprocess library, such as envoy for python. Or you could just write several separate programs in C, and write another "master" program to use fork and pipe to spawn and communicate with the subprocesses.

This is the opposite of what OP explicitly wants … spawning a process is just as low-level as spawning a thread manually. OP is interested in high-level abstractions of concurrency.
–
Konrad RudolphMar 12 '12 at 18:33