Renaming EBEDD to Dispatcher, EBEDWSD to BalancingDispatcher, ThreadBasedDispatcher to PinnedDispatcher and PEBEDD to PriorityDispatcher, closing ticket #784

This commit is contained in:
Viktor Klang 2011-05-20 22:41:41 +02:00
parent 1f024f1c9e
commit 3181905fed
28 changed files with 156 additions and 156 deletions

View file

@ -18,7 +18,7 @@ The event-based Actors currently consume ~600 bytes per Actor which means that y
Default dispatcher
------------------
For most scenarios the default settings are the best. Here we have one single event-based dispatcher for all Actors created. The dispatcher used is globalExecutorBasedEventDrivenDispatcher in akka.dispatch.Dispatchers.
For most scenarios the default settings are the best. Here we have one single event-based dispatcher for all Actors created. The dispatcher used is globalDispatcher in akka.dispatch.Dispatchers.
But if you feel that you are starting to contend 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. See below for details on which ones are available and how they can be configured.
@ -59,11 +59,11 @@ Let's now walk through the different dispatchers in more detail.
Thread-based
^^^^^^^^^^^^
The 'ThreadBasedDispatcher' binds a dedicated OS thread to each specific Actor. The messages are posted to a 'LinkedBlockingQueue' which feeds the messages to the dispatcher one by one. A 'ThreadBasedDispatcher' 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 this dispatcher is that Actors do not block threads for each other.
The 'PinnedDispatcher' binds a dedicated OS thread to each specific Actor. The messages are posted to a 'LinkedBlockingQueue' 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 this dispatcher is that Actors do not block threads for each other.
.. code-block:: java
Dispatcher dispatcher = Dispatchers.newThreadBasedDispatcher(actorRef);
Dispatcher dispatcher = Dispatchers.newPinnedDispatcher(actorRef);
It would normally by used from within the actor like this:
@ -71,7 +71,7 @@ It would normally by used from within the actor like this:
class MyActor extends UntypedActor {
public MyActor() {
getContext().setDispatcher(Dispatchers.newThreadBasedDispatcher(getContext()));
getContext().setDispatcher(Dispatchers.newPinnedDispatcher(getContext()));
}
...
}
@ -79,7 +79,7 @@ It would normally by used from within the actor like this:
Event-based
^^^^^^^^^^^
The 'ExecutorBasedEventDrivenDispatcher' binds a set of Actors to a thread pool backed up by a 'BlockingQueue'. This dispatcher is highly configurable and supports a fluent configuration API to configure the 'BlockingQueue' (type of queue, max items etc.) as well as the thread pool.
The 'Dispatcher' binds a set of Actors to a thread pool backed up by a 'BlockingQueue'. This dispatcher is highly configurable and supports a fluent configuration API to configure the 'BlockingQueue' (type of queue, max items etc.) as well as the thread pool.
The event-driven dispatchers **must be shared** between multiple Typed Actors and/or Actors. One best practice is to let each top-level Actor, e.g. the Actors you define in the declarative supervisor config, 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 design and implement your system in the most efficient way in regards to performance, throughput and latency.
@ -109,7 +109,7 @@ Here is an example:
class MyActor extends UntypedActor {
public MyActor() {
getContext().setDispatcher(Dispatchers.newExecutorBasedEventDrivenDispatcher(name)
getContext().setDispatcher(Dispatchers.newDispatcher(name)
.withNewThreadPoolWithLinkedBlockingQueueWithCapacity(100)
.setCorePoolSize(16)
.setMaxPoolSize(128)
@ -120,7 +120,7 @@ Here is an example:
...
}
This 'ExecutorBasedEventDrivenDispatcher' allows you to define the 'throughput' it should have. This defines the number of messages for a specific Actor the dispatcher should process in one single sweep.
This 'Dispatcher' allows you to define the 'throughput' it should have. This defines the number of messages for a specific Actor the dispatcher should process in one single sweep.
Setting this to a higher number will increase throughput but lower fairness, and vice versa. If you don't specify it explicitly then it uses the default value defined in the 'akka.conf' configuration file:
.. code-block:: xml
@ -136,10 +136,10 @@ Browse the :ref:`scaladoc` or look at the code for all the options available.
Priority event-based
^^^^^^^^^^^^^^^^^^^^
Sometimes it's useful to be able to specify priority order of messages, that is done by using PriorityExecutorBasedEventDrivenDispatcher and supply
Sometimes it's useful to be able to specify priority order of messages, that is done by using PriorityDispatcher and supply
a java.util.Comparator[MessageInvocation] or use a akka.dispatch.PriorityGenerator (recommended):
Creating a PriorityExecutorBasedEventDrivenDispatcher using PriorityGenerator:
Creating a PriorityDispatcher using PriorityGenerator:
.. code-block:: java
@ -168,7 +168,7 @@ Creating a PriorityExecutorBasedEventDrivenDispatcher using PriorityGenerator:
// We create an instance of the actor that will print out the messages it processes
ActorRef ref = Actors.actorOf(MyActor.class);
// We create a new Priority dispatcher and seed it with the priority generator
ref.setDispatcher(new PriorityExecutorBasedEventDrivenDispatcher("foo", gen));
ref.setDispatcher(new PriorityDispatcher("foo", gen));
ref.start(); // Start the actor
ref.getDispatcher().suspend(ref); // Suspending the actor so it doesn't start to treat the messages before we have enqueued all of them :-)
@ -196,14 +196,14 @@ lowpriority
Work-stealing event-based
^^^^^^^^^^^^^^^^^^^^^^^^^
The 'ExecutorBasedEventDrivenWorkStealingDispatcher' is a variation of the 'ExecutorBasedEventDrivenDispatcher' 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 have less messages to process. This can be a great way to improve throughput at the cost of a little higher latency.
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 have less messages to process. This can be a great way to improve throughput at the cost of a little higher latency.
Normally the way you use it is to define a static field to hold the dispatcher and then set in in the Actor explicitly.
.. code-block:: java
class MyActor extends UntypedActor {
public static MessageDispatcher dispatcher = Dispatchers.newExecutorBasedEventDrivenWorkStealingDispatcher(name).build();
public static MessageDispatcher dispatcher = Dispatchers.newBalancingDispatcher(name).build();
public MyActor() {
getContext().setDispatcher(dispatcher);
@ -236,7 +236,7 @@ Per-instance based configuration
You can also do it on a specific dispatcher instance.
For the 'ExecutorBasedEventDrivenDispatcher' and the 'ExecutorBasedWorkStealingDispatcher' you can do it through their constructor
For the 'Dispatcher' and the 'ExecutorBasedWorkStealingDispatcher' you can do it through their constructor
.. code-block:: java
@ -246,13 +246,13 @@ For the 'ExecutorBasedEventDrivenDispatcher' and the 'ExecutorBasedWorkStealingD
Duration pushTimeout = new FiniteDuration(10, TimeUnit.SECONDS);
MailboxType mailboxCapacity = new BoundedMailbox(false, capacity, pushTimeout);
MessageDispatcher dispatcher =
Dispatchers.newExecutorBasedEventDrivenDispatcher(name, throughput, mailboxCapacity).build();
Dispatchers.newDispatcher(name, throughput, mailboxCapacity).build();
getContext().setDispatcher(dispatcher);
}
...
}
For the 'ThreadBasedDispatcher', it is non-shareable between actors, and associates a dedicated Thread with the actor.
For the 'PinnedDispatcher', it is non-shareable between actors, and associates a dedicated Thread with the actor.
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") if the message cannot be added to the mailbox within the time specified by the pushTimeout.
.. code-block:: java
@ -261,7 +261,7 @@ Making it bounded (by specifying a capacity) is optional, but if you do, you nee
public MyActor() {
int mailboxCapacity = 100;
Duration pushTimeout = new FiniteDuration(10, TimeUnit.SECONDS);
getContext().setDispatcher(Dispatchers.newThreadBasedDispatcher(getContext(), mailboxCapacity, pushTimeout));
getContext().setDispatcher(Dispatchers.newPinnedDispatcher(getContext(), mailboxCapacity, pushTimeout));
}
...
}