Imagine that you just bought a brand new Super McAwesome 500-core computer. Dommage-pour-toi, all your applications can only use one core at a time. Doh. Well, what if there was a language that increased its performance linearly with the number of cores/threads? Luckily for you, there is! And it’s name is Erlang.
I generally try to learn something new every once in a while (outside of work classes), since there have been studies showing that learning new things helps your brain stay in shape. After looking around for a while, I decided that I’d give functional programming a shot. (There is a longer, but clearer article, about functional programming here.) It seems like this would be a good way to learn a new way to think about programming, and so far, I’m really loving it.
One of the first things that Erlang impressed me with was the ability to write quicksort in 2 lines:
quicksort() -> ; quicksort([X|Xs]) -> quicksort([Y || Y<-Xs, Y =< X]) ++ [X] ++ quicksort([Y || Y<-Xs, Y > X]).
Compare this to a quicksort in C++ or Java. After seeing that, I decided Erlang was worth the effort.
As I mentioned above, Erlang can scale linearly with the amount of processing cores that you give it. This is because functional programming is “stateless”. That is, it has no global variables or objects. A function’s output is based solely on its inputs (which also makes unit testing a breeze), so there is no need for mutexes or semaphores. The absence of mutexes and semaphores is a sizable speed boost by itself, but think about it a little more. If a function’s output is only based on it’s inputs, you can run that function on as many cores as you have without having to worry about side effects. This is how Erlang, and functional programming in general, can deliver massive gains when given a parallel system.
How is this possible? Well, Erlang is built on its own virtual machine, somewhat like Java. An Erlang thread or process is very quick and cheap to make in the Erlang virtual machine. This is because Erlang doesn’t use typical operating system threads and processes. Rather, the Erlang virtual machine creates one operating system thread per core when starting, to ensure all cores are being used fully. On top of these operating system threads, Erlang creates and manages the lightweight threads and processes.
Because of the different ways that Erlang creates threads, it is dramatically faster than Java. Many more processes can also be created, since the Erlang virtual machine is handling all the overhead, rather than the operating system. Due to how inexpensive these threads and processes are, the way Erlang uses available cores, and functional programming paradigms, making a program work in parallel is not only doable in Erlang, but easily can offer a linear improvement in speed as more resources become available.
Erlang definitely has a different thought pattern that you need to follow though. For instance, variables can only have a value assigned to them once. This means your typical for(i=0; i<10;i++) is out of the question. Instead, you have to use lots and LOTS of recursion.
Now I know what you’re thinking (well, maybe not), “But wouldn’t lots of recursion be slow and waste resources?” Actually, no. Erlang is super optimized to use tail recursion. This basically means the recursion is done in place on the stack, so you can do as much recursion as you want in a constant amount of space. It’s really a very cool concept.
I’m really excited about learning Erlang and functional programming. Right now, I’m merely scratching the surface, but I’m going to dig deeper into it. I plan to post more about my experiences with Erlang and the lessons I learn from functional programming.