-
Notifications
You must be signed in to change notification settings - Fork 402
Agent Concurrency Model
(Not to be confused with the Agrona Agent logging)
Agrona provides a mechanism for encapsulating units of work and running them in using an arbitrary threading setup.
The key interface is the Agent, which is similar in a few ways to Java's Runnable
interface in that there are various ways that a Runnable can be executed (e.g. as a Thread, submitted to a thread pool, etc).
However, there is an important distinction.
The key execution method of the Agent
interface is the doWork
method.
The purpose of this method is not to run indefinitely, but do a bounded amount of work then return and indicate how much work has been done.
E.g. the number of messages processed.
The purpose of have a unit which does a small amount of work then returns is so that multiple instances of these can be run together on the same thread if required.
This is very similar to a co-operative multi-tasking system.
Building a system out of a number of agents in the manner allows for a lot of flexibility with regards to thread and CPU usage.
Most commonly the Aeron Media Driver bus uses agents for each of its core execution units (reciever, sender, conductor), having each implemented as agents means that the Media Driver can run all three in one thread, spread them across separate threads, or even not run them at all, but give the caller an interface to call to run the Media Driver's agents itself.
There are some key constraints to the implementation of an Agent
that the user should be aware of.
Mostly that the work should be bounded and should not block for any extended length of time.
Doing so could mean that other Agent
instances would get starved of resources.
The main class used to run agents is the AgentRunner
which allows one or more agents to be run together under a single Runnable
interface.
This is the glue between the Agrona concurrency model and Java's.
The AgentRunner
can then be launched in a thread or submitted to a thread pool or whichever model the user likes to take.
Because the Agent model is poll based, we need to have a way for the system to back off its use of the CPU, especially when there is no work to do.
This is the reason why the doWork
method returns an integer value.
If no work is done, then it will return 0, which means that the IdleStrategy
can decide to back off from the CPU in whichever way it prefers (yield, sleep, spin...).
Agents are not prescriptive with regards to how they send messages between each other. This can be handled in whatever manner is most useful for the caller (queues, ring buffers, networking) as long as the Agent itself does not block.