Actor Model of Concurrency: Theory Behind & Practical Implementation
Several threads need to coincide to harness the processing power of a machine and make a piece of software as fast as possible. This is where concurrent computing and its sibling, parallel computing, come in.
The actor model of concurrency is one way to design software that executes several threads at the same time. Under this model, everything is an actor. (Yes, it sounds just like the “everything is an object” axiom in object-oriented programming.) Actors, in their turn, are based on asynchronous message passing.
At Wellnuts, we spend our share of time engaging in concurrent computing while building high-load data processing or scalable cloud solutions. So today, let us share our expertise. Below, we’ll break down the benefits, downsides, and implementation examples of the actor model of concurrency.
Actor Model Concurrency: 4 Benefits
What makes the actor model of concurrency a better alternative to other concepts, such as communicating sequential processes (CSP) or multithreading?
Here are four benefits of this model that can answer this question:
- It removes the need for lock-based synchronization. Actors can change only their private state; other actors’ states are off-limits to them. There’s no shared state in the actor model, so there’s no possibility of that disaster when multiple threads try to modify the same data.
- It was designed for distributed computing. Every actor has a mailbox that stores messages until they can be processed. It doesn’t matter if the actor runs locally or on another device. As long as it can receive messages, it makes no difference. That’s a major difference compared to CSP.
- It allows for better scalability. If your actor-based solution sees an increase in traffic load, you can create more actors and assign them the same address. Actors can also be programmed to create child actors under certain conditions. This makes scaling an application a lot easier.
- It doesn’t require the sender to block waiting for a return value. This is an overall benefit of using messaging instead of method calls. The receiver will send a return value in another message when it’s done handling the original one. The sender can send out more messages in the meantime.
Actor Model Concurrency: 3 Downsides
Actor-based concurrency comes with some drawbacks, too. Here are three of them:
- Actors process messages one at a time. So, if several actors send five messages to the same receiving actor, it’ll execute them one after the other. If you need these messages executed simultaneously, you’ll need five different actors running simultaneously.
- Deadlock is still possible. Two actors may end up waiting for a message from each other, thus creating a deadlock. Overall, the model is considered susceptible to deadlocks. (However, it’s worth noting that concurrent programming, in general, is more error-prone and complex than sequential programming.)
- You need to enforce message immutability. Using the actor model in languages that don’t enforce immutability out of the box means it’s up to the developer to ensure messages remain immutable. If this verification is overlooked, messages may become mutable — and lead to thread-safety concerns.
- Unexpected failures can be critical. If an actor failure occurs, other actors may get perpetually stuck awaiting a message from it — a message that won’t arrive because of the failure. To avoid this situation, developers have to employ defensive programming techniques and handle exceptions within the scope of each actor.
Actor Model Concurrency in Programming
This concurrency model has been implemented in multiple programming languages. They include Erlang, Ruby, Dart, and Swift (out-of-the-box support). You’ll have to use external libraries and frameworks for other languages like Java, .NET, JavaScript, C, and C++.
For example, the Akka Actors library is available for Java and Scala. The Cloudl framework, in turn, supports 15 languages, from Python and PHP to C++ and JavaScript.
Let’s take a closer look at the implementation of actor model concurrency in three programming languages: Elixir, Java, and Haskell.
Actor Model Concurrency in Elixir
Elixir is a concurrent programming language that runs on the same virtual machine as Erlang. Companies like Discord, Pinterest, and Moz use it.
Elixir supports actor-based programming out of the box. It allows for creating shared-nothing architecture solutions without installing additional libraries or frameworks. So, you won’t have to deal with compatibility issues that may come with using external tools in development.
On top of that, Elixir provides a solution for two downsides of the actor model of concurrency: enforcing message immutability and handling unexpected failures. First, as it’s a functional language, it enforces the immutability of all data by default. Second, it focuses on post-crash system recovery instead of crash prevention, employing the “let it crash” philosophy.
In Elixir, actors are called processes. You can create them using the spawn function. Message passing is executed by calling send with a process ID and a message. To receive the message, the process should call receive.
Actor Model Concurrency: Java Implementation
One of the most popular technologies (#6 in StackOverflow’s 2022 ranking), Java is widely used in client-server web apps. It supports the concurrent programming paradigm in the core libraries. However, you’ll need an external framework like Akka or Cloudl to implement the actor model of concurrency.
Another peculiarity of Java is that, since it’s an object-oriented language, every actor is an object. So is every message. This is reflected in most actor frameworks for Java, which can make the implementation of the model a bit bizarre for developers.
The model’s “no shared state” axiom may mean trouble if you attempt to implement it mid-development or in legacy Java code. That’s because nothing is stopping you from sharing the state in the programming language itself — by default, it’s allowed.
Akka Actors is one of the most popular actor libraries for Java developers seeking to use the actor model in their solutions. Every Akka actor extends the abstract class AbstractActor. The library also adds three default actors to the application: root (/), user (/user), and system (/system) guardian actors.
Developers praise Akka Actors for its performance on minimal hardware, ease of decoupling, outstanding support, and an abundance of tutorials. However, it’s not the only toolkit allowing actor model implementation in Java. Here are three alternatives for it:
- Cloudl
- ReActed
- Quasar
Actor Model Concurrency in Haskell
Haskell is a purely functional programming language that supports multiple concurrency models on the GHC (Glasgow Haskell Compiler) level. It does so using lightweight threads and high-level abstraction. This allows for high-performance concurrency implementation.
To use the actor model of concurrency in Haskell, you’ll need to use the Hactors library. It allows using Erlang-like actors on top of the GHC concurrency, with some minor tweaks.
In Hactors, actors are processes associated with a message box. Processes are, in their turn, virtual machine threads.
Overall, Haskell gives developers an opportunity to implement the actor model concurrency fairly straightforwardly. As it’s designed with concurrency in mind, Haskell also makes it easier to create performant applications without mutability issues.
In Conclusion
On the one hand, actor-based programming comes with undeniable benefits. They include no shared state, better scalability, and easier distributed solution implementation. On the other hand, it’s not without its caveats: potential deadlocks, steep learning curve, and sequential message processing.
If you opt for the actor model of concurrency, Elixir has one major advantage over most other programming languages. It’s designed with this model in mind. However, if you want to implement actor-based processes in Java code, it’s also possible thanks to tools like Akka Actors.
Need some help in pinpointing which programming language will be a better match for your goals? We at Wellnuts are here for you! We have 10+ years of experience developing high-load data processing, cloud computing, and Internet of Things solutions. Drop us a line to discuss your project!
Ready to talk? Contact us: ask@wellnutscorp.com