Skip to content

ActorsInDetail

devlaam edited this page Apr 7, 2023 · 1 revision

Actors in Detail

Actors working together

To get a feeling how actors work together have a look at the picture below. As stated actors are pieces of code that perform their work in one thread, independent and possibly in parallel with other actors. The thread as depicted as the green, downwards pointing arrows. Each actor labeled A,B etc has some operations inside and instructions with sending the results to other actors that may process them further.

Four actors with messages

For example, actor A performs some calculation, and then sends the result calc to actor B by message 1. This actor processes it further and sends the result res to both actor P by message 2 and Q by message 3. Subsequently those actors send their results around, and some of them may reach actor R.

The idea of this model is that the problem at hand is broken down into small pieces that can be executed with the given information. This can completely be done within the actor, and thus within one thread. As soon as information from the outside world is required to proceed, the actor does not pause, but sends the partial result to a new actor, which will continue as soon as that extra piece of information is collected as well.

In this way it may be so that the majority of actors is waiting for information whereas some are actually running. In an ideal design, the number of actors capable of running equals the number cores/threads the hardware is able to provide. That way the complete task is processed in the quickest possible manner.

The library user/programmer of course has to decompose the complete task into small parts with the property of being independently executed, but never has to spend any thoughts on thread synchronization or carry futures around. Deadlocks can not occur (provided the programmer does not make explicit use of synchronization and only sends immutable data structures around)

Internals of an actor

Within each actor there exists some kind of structure to be able to perform the tasks. First, at creation, actors are often configured with immutable data from the outside world. This data is then passed as parameter to the constructor. Second, each actor is, after creation, brought to the state where it is able to perform the tasks that will enter the mailbox. This is done by startup code in the constructor that sets the some parameters to their correct value and is programmed by the library user.

Internals of an actor

Behind the scenes, the actor contains a mailbox which catches all messages send to the actor, and calls a receive method on each of them. This happens as soon as the scheduler has a time slot available. User code processes the messages, and as a result may change its internal state or send messages to other actors. Alternatively it may also ignore the message altogether of course. Further, all kinds of changes in the internal state of the actor may be communicated to the user by making use of callbacks. These are methods that carry information if the actor has been stopped for example, or if an exception did occur. The user can than take appropriate action.

Sending messages between actors

The way messages are handled between actors requires some special attention. If we take the message stream from the first paragraph and assume all actors are executed on a device with just one single core the following may be the situation.

Message passing in singe thread

The actors are executed in an ordered way like A,B,C ... P,Q,R. This implies that the message stream is predictable and that, after message 1 reaches B messages 2 and 3 reaches P and Q subsequently where P handles 2 first and produces 4, after which Q handles 3 and produces 5. Actor R will see the result 4 before 5 and process them in that order.

In case we have multiple cores in our system a different situation may arise.

Message passing in multiple threads

In this example the first thread processes actors A,B and C and the second thread P,Q and R. Then it may happen that, at the moment actor B produces messages 2 and 3, actor Q is scheduled to run so that actor Q processes message 3 and produces 5 before actor P processes 2 and produces 4. In this situation actor R will process message 5 before 4.

So, in general there is no way for the user to know in which order messages will arrive in the mailbox. If a specific order is required, the actor must first collect all the messages that are expected, sort them, and subsequently process them in the required order.

There is one exception though. If an actor A sends two messages directly to the same actor P, the actor system guarantees that P will process them in the order that A send them.

Internals of an actor

Clone this wiki locally