Concurrency in Elixir

Buddhika Chathuranga
RuntimeError
Published in
5 min readApr 15, 2020

If you have read my previous articles, you may know I am a kind of a parallel computing geek. So this is the reason. If you have pay for a PC đŸ’» and if that PC has two or more cores (Nowadays almost all the processor have more that one core), obviously you have to pay for those core even you are not consuming. In this case, I think you are a developer. Otherwise, it’s not up to you to decide whether you will consume all those cores 😛. So if you have pay for those, why don’t you consume it. Cores are expensive 💾.

Still confused 😕. Let me explain. First, let’s see how many cores do you have on your PC đŸ’». If you are in a windows machine just open the Task Manager and navigate to the Performance tab. You can easily find how many cores do you have.

If you are in Linux just type nproc you will get the number of core you have, or type lscpu and you can find more information about your processor. I had 4 cores on my laptop when I was writing this article. That means, if I consider this, I could have consumed my processor 4 times more than I’m consuming now.

Now I trust, as a developer, you have written millions of code lines in your laptop and have run. Now ask yourself, at least a single time did you consider consuming all those core with your awesome code. If the answer is no, don’t be upset. In the beginning, I event didn’t know there is such a thing called core rather than the processor.

The tragic story is this is the situation of many software companies. Just imagine, of all the developers out there (I mean careless developers like me 😜) consider about consuming all those core, how much energy they could have save for the world, just by not running several servers to do a task which they could have been done with less number of servers 😐. Per SE I said that it doesn’t mean that they did not need to consume their servers efficiently. There are many practical issues when writing code in a way that using all the cores. It is hard to write the synchronized code, which is using all the cores. Read this article to learn much better, why it is a hard thing to write concurrent codes.

This is where Elixir comes to the stage. Elixir is an awesome programming language that is run on Erlang VM (BEAM), which helps you to write software with concurrency. If you have studied concurrent programming before, you might have heard, process, thread, thread pool, locks, mutual exclusion, race conditions, deadlock, etc. and these words like the silence before the storm. But trust me, Elixir will save you. Keep in mind, this doesn’t mean, now it is a piece of cake to develop concurrent software with Elixir.

Highly concurrent systems aren’t easy to write, but with Elixir, the language is on your side

Now let’s see what’s happening to underline the Elixir to achieve concurrency. Elixir using the message passing method rather than shared memory and locks to communicate between processes (Read this article to learn more about inter-process communication). Elixir is using The Actor Model for this. An actor is a single-threaded process, which can make local decisions, create more actors, send more messages, and determine how to respond to the text message received.

Actor has these properties.

  • Mail Box đŸ“«
  • Process ID 🆔

The mailbox is like the very mailbox in your house and the Process ID the same as the address of your house. Refer to this image.

Downloaded from https://rollout.io/blog/concurrency-in-elixir/

Implementation

Create a new process

Now let’s see how to write concurrent code in Elixir with this actor model. Let’s create a sample function to learn this.

We can use spawn/3 function to run this process asynchronously.

iex> pid = spawn(Example, :add, [3, 5])

This will return the Process ID of the newly created process and write 8 to stdout. This newly created process is an Actor.

Message Passing

You already know inter-process communication makes concurrency much harder. Now let’s see how we can pass messages between processes in Elixir. In Elixir there are concepts for this: send/2 and receive. We can send messages to processes by their Process ID and receive using pattern matching to receive messages.

Now lets create a new process from this function and send some messages to that process.

iex> pid = spawn(Example, :messageReceiver, [])iex> send pid, {:ok, "hello"}
hello there
{:ok, "hello"} messageR
iex> send pid, {:ok, "who are you"}
I am a Elixir Process
{:ok, "who are you"}
iex> send pid, {:ok, "how are you"}
{:ok, "how are you"}

messageReceiver function catch {:ok, “hello”} and {:ok, “who are you”} messages and execute procedures bind to it.Here for {:ok, “hello”} message it writes “hello there” to stdout and for {:ok, “who are you”} message write “I am an Elixir process” to stdout. messageReceiver function not looking for a message like {:ok, “how are you”} and it just doesn’t care that message. You can see messageReceiver function working recursively not to stop after catching the first message.

Process linking

In Elixir we can use spawn_link to link a process to another process. So the parent process can notify if the child process crashed.

iex> Example.run()
Process crashed: reason - crashed

The run function creates a new process from iamgoingtocrash function and links that process to the parent process. When the child process crashed it parent can notify with {:EXIT, _from_pid, reason} type message.

These are the very basic concepts of implementing concurrency in Elixir. If you are interested to learn more read the following articles.

Now you may wonder, where are those consuming all the cores thing happen. BEAM is responsible for that. BEAM is the Erlang virtual machine and our Elixir code will run on that VM. Read this article to understand how BEAM designed to use all the cores in your PC.

This is all that I’m going to discuss in this article. So if you want to become a parallel computing geek, you better add Elixir into your toolkit.

--

--