2011-05-17 16:34:07 +02:00
.. _dispatchers-scala:
2011-04-09 19:55:46 -06:00
Dispatchers (Scala)
===================
2011-04-26 21:52:45 +02:00
.. sidebar :: Contents
.. contents :: :local:
2011-12-14 15:12:40 +01:00
2011-04-09 19:55:46 -06:00
The Dispatcher is an important piece that allows you to configure the right semantics and parameters for optimal performance, throughput and scalability. Different Actors have different needs.
2011-04-20 21:12:46 +02:00
Akka supports dispatchers for both event-driven lightweight threads, allowing creation of millions of threads on a single workstation, and thread-based Actors, where each dispatcher is bound to a dedicated OS thread.
2011-04-09 19:55:46 -06:00
2011-06-13 16:47:18 +02:00
The event-based Actors currently consume ~600 bytes per Actor which means that you can create more than 6.5 million Actors on 4 GB RAM.
2011-04-09 19:55:46 -06:00
Default dispatcher
------------------
2011-12-12 21:20:32 +01:00
For most scenarios the default settings are the best. Here we have one single event-based dispatcher for all Actors created.
The default dispatcher is available from the `` ActorSystem.dispatcher `` and can be configured in the `` akka.actor.default-dispatcher ``
section of the :ref: `configuration` .
2011-04-09 19:55:46 -06:00
2011-12-13 15:37:16 +01:00
If you are starting to get contention on the single dispatcher (the `` Executor `` and its queue) or want to group a specific set of Actors
for a dedicated dispatcher for better flexibility and configurability then you can override the defaults and define your own dispatcher.
2011-12-12 21:20:32 +01:00
See below for details on which ones are available and how they can be configured.
2011-04-09 19:55:46 -06:00
Setting the dispatcher
----------------------
2011-12-12 21:20:32 +01:00
You specify the dispatcher to use when creating an actor.
2011-04-09 19:55:46 -06:00
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala
2011-12-12 21:20:32 +01:00
:include: imports,defining-dispatcher
2011-04-09 19:55:46 -06:00
Types of dispatchers
--------------------
2011-12-12 21:20:32 +01:00
There are 4 different types of message dispatchers:
2011-04-09 19:55:46 -06:00
2011-12-12 21:20:32 +01:00
* Thread-based (Pinned)
2011-04-09 19:55:46 -06:00
* Event-based
2011-04-12 15:40:09 +02:00
* Priority event-based
2011-12-13 16:18:51 +01:00
* Work-sharing (Balancing)
2011-04-09 19:55:46 -06:00
2011-12-12 21:20:32 +01:00
It is recommended to define the dispatcher in :ref: `configuration` to allow for tuning for different environments.
2011-04-09 19:55:46 -06:00
2011-12-21 19:07:54 +01:00
Example of a custom event-based dispatcher, which can be fetched with `` system.dispatchers.lookup("my-dispatcher") ``
2011-12-13 15:37:16 +01:00
as in the example above:
2011-12-12 21:20:32 +01:00
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-dispatcher-config
2011-12-12 21:20:32 +01:00
Default values are taken from `` default-dispatcher `` , i.e. all options doesn't need to be defined.
.. warning ::
Factory methods for creating dispatchers programmatically are available in `` akka.dispatch.Dispatchers `` , i.e.
2011-12-21 19:07:54 +01:00
`` dispatchers `` of the `` ActorSystem `` . These methods will probably be changed or removed before
2011-12-12 21:20:32 +01:00
2.0 final release, because dispatchers need to be defined by configuration to work in a clustered setup.
2011-04-09 19:55:46 -06:00
Let's now walk through the different dispatchers in more detail.
2011-04-20 21:12:46 +02:00
Thread-based
^^^^^^^^^^^^
2011-12-13 15:37:16 +01:00
The `` PinnedDispatcher `` binds a dedicated OS thread to each specific Actor. The messages are posted to a
`LinkedBlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html> `_
which feeds the messages to the dispatcher one by one. A `` PinnedDispatcher `` cannot be shared between actors. This dispatcher
has worse performance and scalability than the event-based dispatcher but works great for creating "daemon" Actors that consumes
a low frequency of messages and are allowed to go off and do their own thing for a longer period of time. Another advantage with
2011-12-12 21:20:32 +01:00
this dispatcher is that Actors do not block threads for each other.
2011-04-20 21:12:46 +02:00
2011-12-13 16:18:51 +01:00
The `` PinnedDispatcher `` can't be configured, but is created and associated with an actor like this:
2011-04-20 21:12:46 +02:00
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala#defining-pinned-dispatcher
2011-04-20 21:12:46 +02:00
2011-04-09 19:55:46 -06:00
Event-based
^^^^^^^^^^^
2011-12-13 15:37:16 +01:00
The event-based `` Dispatcher `` binds a set of Actors to a thread pool backed up by a
`BlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html> `_ . This dispatcher is highly configurable
2011-12-12 21:20:32 +01:00
and supports a fluent configuration API to configure the `` BlockingQueue `` (type of queue, max items etc.) as well as the thread pool.
2011-04-09 19:55:46 -06:00
2011-12-13 15:37:16 +01:00
The event-driven dispatchers **must be shared** between multiple Actors. One best practice is to let each top-level Actor, e.g.
the Actors you create from `` system.actorOf `` to get their own dispatcher but reuse the dispatcher for each new Actor
that the top-level Actor creates. But you can also share dispatcher between multiple top-level Actors. This is very use-case specific
and needs to be tried out on a case by case basis. The important thing is that Akka tries to provide you with the freedom you need to
2011-12-12 21:20:32 +01:00
design and implement your system in the most efficient way in regards to performance, throughput and latency.
2011-04-09 19:55:46 -06:00
It comes with many different predefined BlockingQueue configurations:
2011-07-27 11:18:57 +03:00
2011-12-13 14:29:10 +01:00
* Bounded `LinkedBlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html> `_
* Unbounded `LinkedBlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html> `_
* Bounded `ArrayBlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html> `_
* Unbounded `ArrayBlockingQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html> `_
* `SynchronousQueue <http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/SynchronousQueue.html> `_
2011-04-09 19:55:46 -06:00
2011-12-13 15:37:16 +01:00
When using a bounded queue and it has grown up to limit defined the message processing will run in the caller's
2011-12-13 14:29:10 +01:00
thread as a way to slow him down and balance producer/consumer.
2011-04-09 19:55:46 -06:00
2011-12-12 21:20:32 +01:00
Here is an example of a bounded mailbox:
2011-04-09 19:55:46 -06:00
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-bounded-config
2011-04-09 19:55:46 -06:00
2011-07-19 16:20:43 -04:00
The standard :class: `Dispatcher` allows you to define the `` throughput `` it
should have, as shown above. This defines the number of messages for a specific
Actor the dispatcher should process in one single sweep; in other words, the
2011-12-13 14:29:10 +01:00
dispatcher will batch process up to `` throughput `` messages together when
2011-07-19 16:20:43 -04:00
having elected an actor to run. Setting this to a higher number will increase
2011-12-13 15:09:36 +01:00
throughput but lower fairness, and vice versa. If you don't specify it explicitly
2011-12-09 13:27:27 +01:00
then it uses the value (5) defined for `` default-dispatcher `` in the :ref: `configuration` .
2011-04-09 19:55:46 -06:00
Browse the `ScalaDoc <scaladoc> `_ or look at the code for all the options available.
2011-04-12 15:40:09 +02:00
Priority event-based
2011-04-26 21:52:45 +02:00
^^^^^^^^^^^^^^^^^^^^
2011-04-12 15:40:09 +02:00
2011-10-04 20:10:04 +02:00
Sometimes it's useful to be able to specify priority order of messages, that is done by using Dispatcher and supply
2011-12-13 15:37:16 +01:00
an UnboundedPriorityMailbox or BoundedPriorityMailbox with a `` java.util.Comparator[Envelope] `` or use a
2011-12-13 16:18:51 +01:00
`` akka.dispatch.PriorityGenerator `` (recommended).
2011-04-12 15:40:09 +02:00
2011-12-21 20:34:46 +01:00
Creating a Dispatcher with a mailbox using PriorityGenerator:
2011-04-12 15:40:09 +02:00
2011-12-21 20:34:46 +01:00
Config:
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala
:include: prio-dispatcher-config
Priority mailbox:
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala
:include: prio-mailbox
Usage:
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala
:include: prio-dispatcher
2011-04-12 15:40:09 +02:00
2011-12-13 16:18:51 +01:00
Work-sharing event-based
2011-04-09 19:55:46 -06:00
^^^^^^^^^^^^^^^^^^^^^^^^^
2011-12-13 15:37:16 +01:00
The `` BalancingDispatcher `` is a variation of the `` Dispatcher `` in which Actors of the same type can be set up to
share this dispatcher and during execution time the different actors will steal messages from other actors if they
2011-12-14 15:12:40 +01:00
have less messages to process.
2011-12-13 16:18:51 +01:00
Although the technique used in this implementation is commonly known as "work stealing", the actual implementation is probably
2011-12-14 15:12:40 +01:00
best described as "work donating" because the actor of which work is being stolen takes the initiative.
2011-12-13 16:18:51 +01:00
This can be a great way to improve throughput at the cost of a little higher latency.
2011-04-09 19:55:46 -06:00
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-balancing-config
2011-04-09 19:55:46 -06:00
Here is an article with some more information: `Load Balancing Actors with Work Stealing Techniques <http://janvanbesien.blogspot.com/2010/03/load-balancing-actors-with-work.html> `_
Here is another article discussing this particular dispatcher: `Flexible load balancing with Akka in Scala <http://vasilrem.com/blog/software-development/flexible-load-balancing-with-akka-in-scala/> `_
Making the Actor mailbox bounded
--------------------------------
Global configuration
^^^^^^^^^^^^^^^^^^^^
2011-12-13 15:37:16 +01:00
You can make the Actor mailbox bounded by a capacity in two ways. Either you define it in the :ref: `configuration` file under
`` default-dispatcher `` . This will set it globally as default for the DefaultDispatcher and for other configured dispatchers,
2011-12-12 21:20:32 +01:00
if not specified otherwise.
2011-04-09 19:55:46 -06:00
.. code-block :: ruby
2011-12-12 21:20:32 +01:00
akka {
actor {
default-dispatcher {
2011-12-14 15:12:40 +01:00
# If negative (or zero) then an unbounded mailbox is used (default)
# If positive then a bounded mailbox is used and the capacity is set to the number specified
task-queue-size = 1000
2011-12-12 21:20:32 +01:00
}
2011-04-09 19:55:46 -06:00
}
}
Per-instance based configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also do it on a specific dispatcher instance.
2011-12-13 16:18:51 +01:00
.. includecode :: code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-bounded-config
2011-04-09 19:55:46 -06:00
2011-04-26 21:52:45 +02:00
2011-12-12 21:20:32 +01:00
For the `` PinnedDispatcher `` , it is non-shareable between actors, and associates a dedicated Thread with the actor.
2011-12-13 15:37:16 +01:00
Making it bounded (by specifying a capacity) is optional, but if you do, you need to provide a pushTimeout (default is 10 seconds).
When trying to send a message to the Actor it will throw a MessageQueueAppendFailedException("BlockingMessageTransferQueue transfer timed out")
2011-12-12 21:20:32 +01:00
if the message cannot be added to the mailbox within the time specified by the pushTimeout.
2011-04-26 21:52:45 +02:00