Understanding the basics of Elixir’s concurrency model
Tags: elixir, processes, concurrency
Published: 2019-01-16 12:51:26

---
title: Understanding the basics of Elixir’s concurrency model
published: true
tags: elixir, processes, concurrency
canonical_url: 
---

*This article was originally published on my blog at [ieftimov.com](https://ieftimov.com/understanding-basics-elixir-concurrency-model).*

If you come from an object-oriented background, you might have tried concurrencyin your favourite OO language before. Your mileage will vary, but in generalOO languages are harder to work with when it comes to concurrency. This is dueto their nature - they are designed to keep state in memory and require moreexpertise and experience to be successful with.

How does Elixir stand up to other languages when it comes to concurrency? Well,for starters just being functional and immutable is a big win - no state tomanage. But also, Elixir has more goodies packing under the hood and in itsstandard library.

Being based on Erlang’s virtual machine (a.k.a. the BEAM), Elixir uses processesto run **any and all code**. Note that from here on any time we mention processes,unless specified otherwise, we are referring to BEAM processes, not OS processes.

Elixir’s processes are isolated from one another, they do not share any memoryand run concurrently. They are very lightweight and the BEAM is capable ofrunning many thousands of them at the same time. That’s why Elixir exposesprimitives for creating processes, communicating between them and variousmodules on process management.

Let’s see how we can create processes and send messages between them.

## Creating processes

One of the simplest (yet powerful) tools in Elixir’s toolbelt is `IEx` - Elixir’sREPL, short for Interactive Elixir. If we jump into `IEx` and run `h self`, wewill get the following output:

```elixir
iex(1)> h self

                      def self()

  @spec self() :: pid()

Returns the PID (process identifier) of the calling process.

Allowed in guard clauses. Inlined by the compiler.

```

As you can see, `self()` is a built-in function in Elixir which returns the PID(process identifier) of the calling process. If you run it in `IEx` it willreturn the PID of `IEx`:

```elixir
iex(2)> self
#PID<0.102.0>

```

Now, just like `IEx` is a BEAM process, with its own PID, it can also createnew processes. In fact, _any BEAM process_ can `spawn` BEAM processes. This isdone using the `Kernel.spawn/1` function:

```elixir
iex(3)> spawn(fn -> 1 + 1 end)
#PID<0.108.0>

```

`spawn/1` creates a new process which invokes the function provided as argument,`fn -> 1 + 1 end`. What you might notice is that we do not see the return valueof the anonymous function because the function ran in a different process. Whatwe get instead is the PID of the spawned process.

Another thing worth noticing is that once we `spawn` a process it will run rightaway, which means that the function will be immediately executed. We can checkthat using the `Process.alive?/1` function:

```elixir
iex(4)> pid = spawn(fn -> 1 + 1 end)
#PID<0.110.0>

iex(5)> Process.alive?(pid)
false

```

While we don’t need to look at the `Process` module in depth right now, it hasquite a bit more functions available for working with processes. You can exploreits documentation [here](https://hexdocs.pm/elixir/Process.html).

Now, let’s look at receiving messages.

## Receiving messages in processes

For the purpose of our example, let’s imagine we open a new `IEx` sessionand we tell the `IEx` process (a.k.a. `self`) that it might receive a messagethat it should react to. If this makes you scratch your head a bit, rememberthat since `IEx` is a BEAM process it can receive messages just like any otherBEAM process.

The messages that we would like our `IEx` process to receive will be:

- tuple containing `:hello` atom and a string with a name (e.g. `{:hello,
"Jane"}`)
- tuple containing the `:bye` atom and a string with a name (e.g. `{:bye,
"John"}`)

When the process receives the message in the first case it should reply with“Hello Jane”, while in the second case it should reply with “Bye John”. If wecould use the `cond` macro in Elixir, it would look something like:

```elixir
cond message do
  {:hello, name} -> "Hello #{name}"
  {:bye, name} -> "Bye #{name}"
end

```

To receive messages in a process we cannot use `cond`, but Elixir provides uswith a function `receive/1` which takes a block as an argument. Althoughit’s not `cond`, it looks very similar to the example above because it lets ususe pattern-matching:

```elixir
receive do
  {:hello, name} -> "Hello #{name}"
  {:bye, name} -> "Bye #{name}"
end

```

What you’re seeing here usage of BEAM’s actor model for concurrency in Elixir.If you’re not familiar with the model worry not - you can read an interestingELI5 about it[here on Dev.to](https://dev.to/amalrik/explain-actor-concurrency-model), or you can just keep on reading and by the end of this article you should have a good idea about it.

The `receive` function takes the received message and tries to pattern-match it to one of the statements in the block. Obviously, it accepts not just a value to return but also a function call. As you can imagine, `receive/1` is what is called when **the mailbox of the process** gets a new message in.

Now that we fixed up the actions on the mailbox of our process, how can we send a message to our `IEx` process?

This is done via the `send/2` function. The function takes the PID and the message itself as arguments. For our example, let’s send the following message to our `IEx` process:

```elixir
iex(1)> send self(), {:hello, "John"}
{:hello, "John"}

```

What you see here is the message being dropped in `IEx`’s mailbox. This means that we need to invoke the `receive` function in our `IEx` session so we can process the messages in the mailbox:

```elixir
iex(2)> receive do
...(2)> {:hello, name} -> "Hello #{name}"
...(2)> {:bye, name} -> "Bye #{name}"
...(2)> end
"Hello John"

```

Right after executing the `receive` block the message will be immediately processed and we will see `"Hello John"` returned.

### What if we never receive a message?

One thing to notice here is that if we would just write the `receive` block in our `IEx` session it would block until the process receives a message.That’s expected - if there is no message in the mailbox matching any of the patterns, the current process will wait until a matching message arrives. This is the default behaviour of `receive/1`.

Obviously, if we get ourselves stuck in such way we can always stop the `IEx` session by using `Ctrl+C`. But, what if a process in our application gets stuck?How can we tell it that it should stop waiting after a certain amount of time if it does not receive a message?

One nicety that Elixir provides us with is setting a timeout using `after`:

```elixir
iex(6)> receive do
...(6)> {:hello, name} -> "Hello #{name}"
...(6)> {:bye, name} -> "Bye #{name}"
...(6)> after
...(6)> 1_000 -> "Nothing after 1s"
...(6)> end
"Nothing after 1s"

```

What happens here is that the timeout function is executed after 1000milliseconds pass and the `receive/1` function exits (hence stops blocking).This prevents processes hanging around waiting forever for a matching message toarrive in their mailboxes.

## Long-running processes

So far we were looking at sending and receiving messages to the same process -the `IEx` process itself. This is quite a simple example and won’t help when we would like to put processes into action in a production application.

At this point, you might be wondering how to actually spawn a process that would react to multiple incoming messages, instead of just (ab)using the `IEx` process with the `receive/1` function.

Well, to do this we have to make a process run infinitely (or until we ask it to die). How? By creating an infinite loop in the process itself.

### WTF you mean by “an infinite loop”?!

Yeah, I know, it feels weird, doesn’t it? Here’s the thing - the BEAM has an optimisation in it, so-called a last-call optimisation (read Joe Armstrong’s explanation of this optimisation[here](http://erlang.org/pipermail/erlang-questions/2016-October/090663.html)),where if the last call in a function is a call to the same function, Elixir will not allocate a new stack frame on the call stack. In fact, it will just jump to the beginning of the same function (instead of running another instance of it), which will prevent a stack overflow happening to our program.

This means that it’s _virtually_ impossible to smash the stack in the BEAM languages (Erlang & Elixir), if we are just a bit careful when composing these self-invoking functions.

### Long-running processes, continued

Let’s look at a small module with a single function:

```elixir
defmodule MyProcess do
  def start do
    receive do
      {:hello, name} ->
        IO.puts "Hello #{name}!"
        start()
      {:bye, name} ->
        IO.puts "Bye #{name}. Shutdown in 3, 2, 1..."
    end
  end
end

```

The `MyProcess.start` function when run will wait for a message to arrive in the process’ mailbox. Then, it will try to pattern match on the arrived message and execute the associated code. One trick is that at the end of the first case we execute the `start` function again, which will create an infinite loop in the process, therefore having the process waiting for messages forever.

Let’s look how this will work in `IEx`:

```elixir
iex(1)> pid = spawn(MyProcess, :start, [])
#PID<0.120.0>

iex(2)> send pid, {:hello, "Ilija"}
Hello Ilija!
{:hello, "Ilija"}

iex(3)> send pid, {:hello, "Jane"}
Hello Jane!
{:hello, "Jane"}

iex(4)> send pid, {:bye, "Jane"}
Bye Jane. Shutdown in 3, 2, 1...
{:bye, "Jane"}

```

First, we use `spawn/3` to create a process that will run the `MyProcess.run` function. `spawn/3` is a flavour of `spawn/1` - the only difference is that `spawn/3` knows how to run a named function in a process, while `spawn/1` takes only anonymous functions as arguments.

Then, you can see that every time we send a `{:hello, "Name"}` message to the process (using `send/2`), we see the process printing back the greeting. Once we send the `{:bye, "Jane"}` message the process prints that it’s shutting down.

How so? Well, if you look at the `MyProcess.start` function you will notice that it does not invoke itself after it prints out the shutdown message. This means that once it handles that message the `MyProcess.start` function will finish and the process will die.

Let’s test that in `IEx`, using the `Process.alive?/1` function:

```elixir
iex(1)> pid = spawn MyProcess, :start, []
#PID<0.109.0>

iex(2)> Process.alive? pid
true

iex(3)> send pid, {:hello, "Ilija"}
Hello Ilija!
{:hello, "Ilija"}

iex(4)> Process.alive? pid
true

iex(5)> send pid, {:bye, "Ilija"}
Bye Ilija. Shutdown in 3, 2, 1...
{:bye, "Ilija"}

iex(6)> Process.alive? pid
false

```

Now that we know how to send and receive multiple messages to a process inElixir, you might be wondering what is a good use-case to use processes for?

The answer is: keeping state.

## Keeping state using processes

You might find this weird, but this is a classic example to keeping state in Elixir. While our example here will not take care of storing state on disk, cover all edge-cases that might occur or be a bullet-proof solution, I hope it will get your brain juices flowing on processes and how to use them.

Let’s write a `Store` module that will have a `start` function. It should spawn a process which will invoke a function of the same module, for now, called `foo`:

```elixir
# store.exs
defmodule Store do
  def start do
    spawn( __MODULE__ , :foo, [%{}])
  end

  def foo(map) do
    IO.puts "Nothing so far"
  end
end

```

Let’s briefly dissect the `Store.start` function: what it does is it `spawn`s anew process calling the `foo/1` function and it passes an empty map (`%{}`) as an argument to the function. If the special keyword ` __MODULE__ ` throws you off, it’s just an alias to the module name:

```elixir
iex(1)> defmodule Test do
...(1)> def eql?, do: __MODULE__ == Test
...(1)> end

iex(2)> Test.eql?
true

```

This means that when we call `Store.start` we will immediately see the output of the function in the process. Right after, the process will die:

```elixir
iex(4)> pid = Store.start
Nothing so far...
#PID<0.117.0>

iex(5)> Process.alive? pid
false

```

This means that we need to make `foo/1` a function that will loop forever. Or at least until we tell it to stop.

Let’s rename `foo/1` to `loop/1` and make it loop forever:

```elixir
defmodule Store do
  def start do
    spawn( __MODULE__ , :loop, [%{}])
  end

  def loop(state) do
    receive do
      loop(state)
    end
  end
end

```

If we run this module now in an `IEx` session the process will work forever. Instead of doing that, let’s add a special “system” message that we can send to the process so we can force it to shut down:

```elixir
defmodule Store do
  def start do
    spawn( __MODULE__ , :loop, [%{}])
  end

  def loop(state) do
    receive do
      {:stop, caller_pid} ->
        send caller_pid, "Shutting down"
      _ ->
        loop(state)
    end
  end
end

```

So now, you see that when there’s no match, the `Store.loop/1` function will just recurse, but when the `:stop` message is received it will just `send` a`"Shutting down"` message to the calling PID.

```elixir
iex(1)> pid = Store.start
#PID<0.125.0>

iex(2)> send pid, {:stop, self()}
{:stop, #PID<0.102.0>}

iex(3)> flush()
"Shutting down."
:ok

```

What you’re seeing here is a very simple example of sending messages between two processes - the `Store` process and our `IEx` session process. When we send the `:stop` message we also send the PID of the `IEx` session (`self`), which is then used by `Store.loop/1` to send the reply back. At the end, instead of writing a whole `receive` block for the `IEx` session we just invoke `flush`,which flushes the `IEx` process mailbox and returns all of the messages in the mailbox at that time.

If you’re feeling deep in the rabbit hole now worry not - we are going to address keeping state in a process right away!

Let’s say that our `Store` will accept four commands:

1. `stop` - the one we already implemented, which stops the `Store` process
2. `put` - adds a new key-value pair to the `state` map
3. `get` - fetches a value for a given key from the `state` map
4. `get_all` - fetches all of the key-value pairs that are stored in the `state` map

### Putting a value

Let’s implement the `put` command:

```elixir
defmodule Store do
  def start do
    spawn( __MODULE__ , :loop, [%{}])
  end

  def loop(state) do
    receive do
      {:put, key, value} ->
        new_state = Map.put(state, key, value)
        loop(new_state)
      {:stop, caller} ->
        send caller, "Shutting down."
      _ ->
        loop(state)
    end
  end
end

```

When we send a tuple containing `{:put, :foo, :bar}` to the process, it will add the `:foo => :bar` pair to the `state` map. The key here is that it will invoke `State.loop/1` again with the updated state (`new_state`). This will make sure that the key-value pair we added will be included in the new state on the next recursion of the function.

### Getting values

Let’s implement `get` so we can test `get` and `put` together via an `IEx` session:

```elixir
defmodule Store do
  def start do
    spawn( __MODULE__ , :loop, [%{}])
  end

  def loop(state) do
    receive do
      {:stop, caller} ->
        send caller, "Shutting down."
      {:put, key, value} ->
        new_state = Map.put(state, key, value)
        loop(new_state)
      {:get, key, caller} ->
        send caller, Map.fetch(state, key)
        loop(state)
      _ ->
        loop(state)
    end
  end
end

```

Just like with the other commands, there’s no magic around `get`. We use `Map.fetch/2` to get the value for the key passed. Also, we take the PID of the `caller` so we can send back to the caller the value found in the map:

```elixir
iex(1)> pid = Store.start
#PID<0.119.0>

iex(2)> send pid, {:put, :name, "Ilija"}
{:put, :name, "Ilija"}

iex(3)> send pid, {:get, :name, self()}
{:get, :name, #PID<0.102.0>}

iex(4)> flush
{:ok, "Ilija"}
:ok

iex(5)> send pid, {:put, :surname, "Eftimov"}
{:put, :surname, "Eftimov"}

iex(6)> send pid, {:get, :surname, self()}
{:get, :surname, #PID<0.102.0>}

iex(7)> flush
{:ok, "Eftimov"}
:ok

```

If we look at the “conversation” we have with the `Store` process, at the beginning, we set a `:name` key with the value `"Ilija"` and we retrieve it after (and we see the reply using `flush`). Then we do the same exercise by adding a new key to the map in the `Store`, this time `:surname` with the value`"Eftimov"`.

From the “conversation” perspective, the key piece here is us sending `self()` -the PID of our current process (the `IEx` session) - so the `Store` process knows where to send the reply to.

### Getting a dump of the store

Right before we started writing the `Store` module we mentioned that we will also implement a `get_all` command, which will return all of the contents of the `Store`. Let’s do that:

```elixir
defmodule Store do
  def start do
    spawn( __MODULE__ , :loop, [%{}])
  end

  def loop(state) do
    receive do
      {:stop, caller} ->
        send caller, "Shutting down."
      {:put, key, value} ->
        new_state = Map.put(state, key, value)
        loop(new_state)
      {:get, key, caller} ->
        send caller, Map.fetch(state, key)
        loop(state)
      {:get_all, caller } ->
        send caller, state
        loop(state)
      _ ->
        loop(state)
    end
  end
end

```

If you expected something special here, I am very sorry to disappoint you. The implementation of the `get_all` command is to return the whole `state` map of the process to the sender.

Let’s test it out:

```elixir
iex(1)> pid = Store.start
#PID<0.136.0>

iex(2)> send pid, {:put, :name, "Jane"}
{:put, :name, "Jane"}

iex(3)> send pid, {:put, :surname, "Doe"}
{:put, :surname, "Doe"}

iex(4)> send pid, {:get_all, self()}
{:get_all, #PID<0.102.0>}

iex(5)> flush
%{name: "Jane", surname: "Doe"}
:ok

```

As expected, once we add two key-value pairs to the `Store`, when we invoke the `get_all` command the `Store` process sends back the whole `state` map.

While this is a very small and contrived example, the skeleton we followed hereby keeping state by using recursion, sending commands and replies back and forth to the calling process is actually used quite a bit in Erlang and Elixir.

## A small disappointment

First, I am quite happy you managed to get to the end of this article.I believe that once I understood the basics of the concurrency model of Elixir,by going through these exercises were eye-opening for me, and I hope they werefor you as well.

Understanding how to use processes by sending and receiving messages is paramount knowledge that you can use going forward on your Elixir journey.

Now, as promised - a small disappointment.

For more than 90% of the cases when you want to write concurrent code in Elixir, you will **not** use processes like here. In fact, you won’t (almost) ever use the `send/2` and `receive/1` functions. Seriously.

Why? Well, that’s because Elixir comes with this thingy called OTP, that will help you do much cooler things with concurrency, without writing any of this low-level process management code. Of course, this should not stop you from employing processes when you feel that you strongly need them, or when you want to experiment and learn.

But, that’s a topic for the next blog post, where we’ll dive more in OTP and some of its behaviours.

Until then, where do you see processes as a potential use case in your projects/work?

### Some more reading

If you would like to read a bit more, here are a couple of links that are worth checking out:

- [Processes](https://elixir-lang.org/getting-started/processes.html) on Elixir’s“Getting started” guide
- [Long-lived processes in Elixir](https://robots.thoughtbot.com/long-lived-processes-in-elixir) by German Velasco on Thoughtbot’s blog
- [Process](https://hexdocs.pm/elixir/Process.html#content) on Hexdocs.pm
- [Endless recursion](https://elixirforum.com/t/endless-recursion/10683) on theElixir Forum