DEV Community

Amalrik Maia
Amalrik Maia

Posted on

Explain Actor concurrency model like I'm five

There are tons of content about this topic, but they are usually dry and hard to grasp. Please explain like im five.

Top comments (2)

centur profile image
Alexey Shcherbak

One of the best abstractions for actors I discovered for myself are "real world" entities. So let's communicate actors concept to 5yo.
Imagine that you're programming real world. You have humans - human is our actor type. They all kind of the same - 2 hands, 2 legs, body and head, so they are the same type, but each human is very unique, and has an absolutely unique name (which is actor ID - "DNA sequence").
So now you, as a world operator (developer), want to perform some work and make this world a bit better place - you start to mail some work tasks to your actors.

This is the only way you can ask humans to do something. Each mail arrives into input mailbox from which it's picked by our human instance. Human, when picks a mail (only one of many of them), process it sequentially, working through the mailbox queue one by one. This approach eliminates many situations when human has 2 or more mails opened simultaneously and the tasks are contradicting each other (or compete for a shared resource, say both want to use actor's right hand).

You can have different types of tasks - for some of them you may want to ask specific human and receive report back from him - your mail would contain a recipient name and return address where to send back report. For some tasks - you're not fast about who will do the work, you just want it to be done, eventually - so you can create a new human for every task and assign him that unique job, and this ensures that your mail with task will not be delayed by any other pending mails in this particular human mailbox. Although be mindful - creation of human actor is "cheap", but not "free".

Also humans are not always work well - they may fall sick or been struck by lightning, so they have to report to their supervisor that they actually can't complete their current task (or actors can die w\o reply so there will be a timeout error @supervisor level). Then supervisor must decide what to do in this case - communicate back to operator that "this task can't be completed" or try to re-create human and try to task him with the same task again.

Now, all humans work independently and they really don't block each other out of CPU resource, so when they have to asynchronously wait for some computation to complete - they allow others to take their turns on CPU and process their tasks, so they are cooperating together for higher concurrency and better resource utilisation.

Humans can interact with other humans and with actors of other types (cars, birds, planes) using the same mailing mechanism.

Normally before sending a message to some actor, operator needs to ensure that actor with such name\ID was created before and operator knows it's name (holds a reference to an instance). There is an extension of actor model, called "virtual actors" (such as in Orleans and Orbit frameworks). They are like "always-exist humans" - operator simply sends a message - and such actor instance automatically created (or if it's already activated - existing instance is used) and task is placed in it's input mailbox.

Using actors of different types and their interactions, developer can easily build and operate very complex programming workflows, with a high throughput because of cooperating concurrency and very few concurrency-related problems (as each actor can process only one task at a time, eliminating many multi-threading problems around shared resource).

kspeakman profile image
Kasey Speakman

Actors are just objects. The difference from normal objects is how you communicate with them and how they are managed.

The only way to communicate with an actor is to post a message to its mailbox. If ActorA needs information from ActorB, it would post a message to ActorB's mailbox. The message would have ActorA's "return address". When ActorB processes the message, it will send the response as a new message to ActorA's mailbox. But maybe ActorA just has work for ActorB and doesn't need a response... no return address.

Actors operate independently of each other, so multiple actors are doing work at any given time. But internally they only process one message at a time (aka single-threaded). This eliminates a large class of issues normally associated with concurrency.

In most distributed actor systems (e.g. Erlang), actors are managed by Supervisors. Supervisors will create new actors, check on their health, and replace failed ones. In actor systems without separate supervision, actors are usually responsible for creating and managing other actors as needed. In essence, specific actors become supervisors in addition to other duties.

The Actor Model of Computation (btw, don't search for just "Actor Model") is most suitable for stateful processing. It can work but fits less precisely with stateless workloads. An example where I've seen it work well is when a large amount of data needs to be loaded per request with frequent requests. Instead, spawn an actor (per entity) to keep the state and handle the very rapid changes. Unload the actor when activity dies down. Persist the state when it unloads (and maybe on a timer).