Actor Model
We’ll explore a concurrency model that makes writing performant, concurrent software much easier than traditional approaches. I’m talking about the Actor Model. In the following sections, we’ll dive into what it is and how it simplifies concurrency challenges that developers dread.
History
Actor model was introduced in 1973 by Carl Hewitt, Peter Bishop and Richard Steiger of MIT in their paper “A Universal Modular Actor Formalism for Artificial Intelligence”. The Artificial Intelligence being talked about is not the GenAI that we talk about but about computational systems in general. It was influenced by programming languages like Lisp, Simula, Smalltalk(which is still considered by many as one of the best Object Oriented Language implementation).
Quoting Wikipedia here, the paper was prospect of highly parallel computing machines with their own local memory and communications processor, communicating via a high-performance communications network. If this seems similar to today’s computers which have very high number of cores, humongous amount of memory and very fast network connections and NICs, it is because it is exactly that. The advent of massive concurrency and hardware improvements over the years and plateauing of single core speeds is what revived the interest in actor model.
There were several theoretical papers about actor model in 1970s and 80s that formalized the model and explored its applications. But most significant development in this model came from Ericsson, which tasked Joe Armstrong, Robert Virding, and Mike Williams to develop a language for building it next generation of telecommunications switches which needed massive concurrency, highly reliable(you don’t want telephone outage just because you are doing a weekly/monthly software release). The model was later implemented in several languages and gained more popularity due to the current software systems which are inherently highly concurrent and the access to multi core machines. Enough about the history, lets dwell into what it is. The details are intentionally simple to make it easier for readers(me!!!) to understand.
What are actors?
We have already spent a lot of time talking about the model without mentioning what they are and how they work.

Anatomy of an actor. Made with excalidraw.
An actor is basically a computational unit, that has following properties:
- Every actor is addressable(they have an address that can be used by any other actor in the system to send messages)
- Receive messages in its mailbox
- Process them one at a time, update its internal state.
- Create more actors
- Respond back to the original caller(that is by using the reference of the original caller from the message)
Some key pointers that make actors perfect for concurrency:
- Message Passing Only: Communication through message passing eliminates shared state, removing most of the concurrency headaches. This removes race conditions and the need of locks and semaphores.
- Encapsulated State: An actor can only modify its internal state, and that state can only be modified by that actor. This isolation means multiple threads would never access this state concurrently.
- Asynchronous Communication: Message passing is asynchronous by default. This allows the system to continue without blocking, massively increasing throughput. Synchronous behavior is emulated using asynchronous reply using caller’s reference.
- Sequential Processing: Only one message can be processed by an actor at a time. This sequential guarantee within each actor eliminates the need for complex synchronization.

Communication between actors. Made with excalidraw.
Some common benefits/side-effects of the Actor model
Since Erlang, the most mature implementation of Actor model, had some strict requirements around fault tolerance and failure isolation, there are some benefits that came into almost every implementation that came after it.
- Functional Programming: Functional programming complements the immutable message passing and state isolation. And with the functional programming paradigm, it brings a lot of benefits around testability and predictability.
- Let it crash: This approach of Erlang essentially means that we should not try to handle all the errors that we do not know how to handle, but at the same time it should not lead to the whole application crashing. This brings concept of Supervision trees where Supervisors are responsible for managing the actors that are created as the children of them. They have strategies on how to bring the crashed processes back.
Real-world Applications
The Actor model shines in scenarios requiring high concurreny, fault tolerance and distributed computing.
- Telecommunication Systems: Erlang and its OTP(Open Telecom Platform) were specifically designed for switches handling millions of concurrent connections.
- Chat Applications: Managing millions of concurrent user sessions.
- Gaming Servers: Handling thousands of simultaneously connected players.
- IoT Systems: Managing Communication with countless connected devices.
- Highly Distributed Databases and Queues: Some highly distributed databases like RabbitMQ and Riak are built on top of Erlang and Elixir.
- Any highly concurrent soft-realtime systems.
Popular Implementations
- Erlang/Elixir: The most mature implementation, built with concurrency, fault tolerance as core principles.
- Akka: A toolkit for building highly concurrent, distributed applications on the JVM.
- Orleans: Microsoft’s actor framework for C#.
How I came across this and why I liked it?
I came across couple of videos about Actor Model that really intrigued me and they were related to Elixir. Those are talks given by Brian Cardarella of DockYard and Jose Valim, the creator of Elixir. Jose Valim was a core contributor of Ruby on Rails and was not happy with the concurrency primitives in Rails. His search for a better approach made him look at BEAM(Erlang Virtual Machine) and Erlang. This inspired him to write a language whose concepts were based on Erlang and the syntax on Rails which is known for its developer friendlyness and productivity. Those videos are the below and I would definitely recommend watching them:
- Elixir: The only Sane Choice in an Insane World • Brian Cardarella • GOTO 2017 - Link
- Phoenix a Web Framework for the New Web • José Valim • GOTO 2016 - Link
These talks really showcase some amazing things that make it really approachable when the previous versions of the Actor Models were not.
Some of the key things that sounded compelling to me:
- Friendly syntax
- Concurrency story
- Location transparency of the processes
- Introspection and observability
- Phoenix framework by Chris McCord. This is a Rails like framework which can be used to create server side rendered applications with a lot of realtime pubsub based features.
These were some of the key benefits that I felt when saw these videos some 7 years ago. Elixir and Phoenix has expanded since. One of that is Phoenix LiveView created by Chris McCord. It is a server side rendered realtime framework that pushes efficient diffs to Client. This makes it easy to write interactive soft realtime web apps without needing a lot of JS. I was completely sold on this dream. Find more about it here.
Example
This is the example Elixir implementation of Counter implemented in Python and Golang in this other article.
defmodule Counter do
def main do
# Start a coordinator process that will collect results
coordinator_pid = spawn_link(__MODULE__, :coordinator, [0, 5])
Enum.each(0..4, fn i ->
# Each spawn creates a new actor with its own isolated state
spawn_link(__MODULE__, :increment_counter, [i + 1, 10, coordinator_pid])
end)
# Wait for the final result and print it
receive do
{:final_result, counter} ->
IO.puts("Final counter value: #{counter}")
after
5000 ->
IO.puts("Timeout waiting for results")
end
end
@doc """
Worker actor that increments a counter and sends the result to the coordinator.
This has a local state. Currently just adds all the numbers by sleeping but it can be anything.
"""
def increment_counter(amount, repeats, coordinator_pid) do
# Each actor maintains its own local state
local_sum = Enum.reduce(1..repeats, 0, fn _, acc ->
Process.sleep(10) # Simulate some work
acc + amount
end)
# Send the result through a message to the coordinator actor
send(coordinator_pid, {:result, local_sum})
end
@doc """
Coordinator actor that collects results from workers and tracks completion.
"""
def coordinator(counter, 0) do
send(Process.group_leader(), {:final_result, counter}) # Send the result back to leader.
end
# counter is the current state. Calls recursively to collect the next result.
def coordinator(counter, remaining_workers) do
receive do # Wait for a message from any worker
{:result, result} ->
new_counter = counter + result # Update internal state and continue with recursion
coordinator(new_counter, remaining_workers - 1)
end
end
end
# Run the program
Counter.main()
The above example shows how easy it is to create new processes that can run concurrently and efficiently.
Some advantages of the above:
- The code is functional which makes testing easy.
- The code is not concurrent inside a single process which makes it easy to reason about.
- No need for channels or shared state to send messaages. If you have the address of the process, you can call it.
- Pattern matching makes code more evident and more readable.
Conclusion and Footnotes
These are some of my thoughts on the Elixir and Actor model as programming paradigm. We have not talked about thel ocation transparency and clustering in Elixir and Erlang but that in itself requires a different blog post. I currently reached for Elixir to build a soft realtime concurrent system that would benefit a lot from the primitives that Elixir and Phoenix gives. To know more about it, stay tuned (my cue for not dropping it in the middle). Lot of content here is not original and not something that is not said before but this is my attempt at formalizing my thoughts about it. Feedback and comments (both negative and positive) are appreciated.
Some Awesome Elixir Resources
The below links are in no particular order. Not an exhaustive link but enough to get anyone trying to get started with Elixir and Erlang.
- Elixir: The only Sane Choice in an Insane World • Brian Cardarella • GOTO 2017 - www.youtube.com/watch?v=gom6nEvtl3U
- Phoenix a Web Framework for the New Web • José Valim • GOTO 2016 - www.youtube.com/watch?v=bk3icU8iIto
- Chris McCord - Keynote: Phoenix LiveView - Interactive Apps without Javascript - ElixirConf EU 2019: www.youtube.com/watch?v=8xJzHq8ru0M&t=2412s
- Phoenix framework - www.phoenixframework.org/
- ElixirDaze 2018 - Building beautiful systems with Phoenix contexts… by Andrew Hao - www.youtube.com/watch?v=l3VgbSgo71E
- The Soul of Erlang and Elixir • Sasa Juric • GOTO 2019 - www.youtube.com/watch?v=JvBT4XBdoUE&t=1260s
- ElixirConf 2021 - Mark Ericksen - Globally Distributed Elixir Apps on Fly.io - www.youtube.com/watch?v=IqnZnFpxLjI