Merge remote-tracking branch 'origin/master' into testing-2.9.2
This commit is contained in:
commit
73170d1f4b
68 changed files with 1342 additions and 1125 deletions
|
|
@ -60,19 +60,17 @@ public class DispatcherDocTestBase {
|
|||
@Test
|
||||
public void defineDispatcher() {
|
||||
//#defining-dispatcher
|
||||
ActorRef myActor1 = system.actorOf(new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"),
|
||||
"myactor1");
|
||||
ActorRef myActor2 = system.actorOf(new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"),
|
||||
"myactor2");
|
||||
ActorRef myActor =
|
||||
system.actorOf(new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"),
|
||||
"myactor3");
|
||||
//#defining-dispatcher
|
||||
}
|
||||
|
||||
@Test
|
||||
public void definePinnedDispatcher() {
|
||||
//#defining-pinned-dispatcher
|
||||
String name = "myactor";
|
||||
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class)
|
||||
.withDispatcher("myactor-dispatcher"), name);
|
||||
.withDispatcher("my-pinned-dispatcher"));
|
||||
//#defining-pinned-dispatcher
|
||||
}
|
||||
|
||||
|
|
@ -80,11 +78,13 @@ public class DispatcherDocTestBase {
|
|||
public void priorityDispatcher() throws Exception {
|
||||
//#prio-dispatcher
|
||||
|
||||
ActorRef myActor = system.actorOf( // We create a new Actor that just prints out what it processes
|
||||
// We create a new Actor that just prints out what it processes
|
||||
ActorRef myActor = system.actorOf(
|
||||
new Props().withCreator(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new UntypedActor() {
|
||||
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
||||
LoggingAdapter log =
|
||||
Logging.getLogger(getContext().system(), this);
|
||||
{
|
||||
getSelf().tell("lowpriority");
|
||||
getSelf().tell("lowpriority");
|
||||
|
|
@ -101,7 +101,7 @@ public class DispatcherDocTestBase {
|
|||
}
|
||||
};
|
||||
}
|
||||
}).withDispatcher("prio-dispatcher-java"));
|
||||
}).withDispatcher("prio-dispatcher"));
|
||||
|
||||
/*
|
||||
Logs:
|
||||
|
|
@ -123,19 +123,20 @@ public class DispatcherDocTestBase {
|
|||
}
|
||||
|
||||
//#prio-mailbox
|
||||
public static class PrioMailbox extends UnboundedPriorityMailbox {
|
||||
public PrioMailbox(Config config) { // needed for reflective instantiation
|
||||
super(new PriorityGenerator() { // Create a new PriorityGenerator, lower prio means more important
|
||||
public static class MyPrioMailbox extends UnboundedPriorityMailbox {
|
||||
public MyPrioMailbox(ActorSystem.Settings settings, Config config) { // needed for reflective instantiation
|
||||
// Create a new PriorityGenerator, lower prio means more important
|
||||
super(new PriorityGenerator() {
|
||||
@Override
|
||||
public int gen(Object message) {
|
||||
if (message.equals("highpriority"))
|
||||
return 0; // 'highpriority messages should be treated first if possible
|
||||
else if (message.equals("lowpriority"))
|
||||
return 100; // 'lowpriority messages should be treated last if possible
|
||||
return 2; // 'lowpriority messages should be treated last if possible
|
||||
else if (message.equals(Actors.poisonPill()))
|
||||
return 1000; // PoisonPill when no other left
|
||||
return 3; // PoisonPill when no other left
|
||||
else
|
||||
return 50; // We default to 50
|
||||
return 1; // By default they go between high and low prio
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import akka.actor.Props;
|
|||
import akka.actor.UntypedActor;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Address;
|
||||
import akka.actor.AddressExtractor;
|
||||
import akka.actor.AddressFromURIString;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RouterViaProgramExample {
|
||||
|
|
@ -73,7 +73,7 @@ public class RouterViaProgramExample {
|
|||
|
||||
//#remoteRoutees
|
||||
Address addr1 = new Address("akka", "remotesys", "otherhost", 1234);
|
||||
Address addr2 = AddressExtractor.parse("akka://othersys@anotherhost:1234");
|
||||
Address addr2 = AddressFromURIString.parse("akka://othersys@anotherhost:1234");
|
||||
Address[] addresses = new Address[] { addr1, addr2 };
|
||||
ActorRef routerRemote = system.actorOf(new Props(ExampleActor.class)
|
||||
.withRouter(new RemoteRouterConfig(new RoundRobinRouter(5), addresses)));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import org.junit.Test;
|
|||
//#import
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Address;
|
||||
import akka.actor.AddressExtractor;
|
||||
import akka.actor.AddressFromURIString;
|
||||
import akka.actor.Deploy;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.ActorSystem;
|
||||
|
|
@ -35,7 +35,7 @@ public class RemoteDeploymentDocTestBase {
|
|||
public void demonstrateDeployment() {
|
||||
//#make-address
|
||||
Address addr = new Address("akka", "sys", "host", 1234);
|
||||
addr = AddressExtractor.parse("akka://sys@host:1234"); // the same
|
||||
addr = AddressFromURIString.parse("akka://sys@host:1234"); // the same
|
||||
//#make-address
|
||||
//#deploy
|
||||
ActorRef ref = system.actorOf(new Props(RemoteDeploymentDocSpec.Echo.class).withDeploy(new Deploy(new RemoteScope(addr))));
|
||||
|
|
|
|||
|
|
@ -1,195 +0,0 @@
|
|||
Dataflow Concurrency (Java)
|
||||
===========================
|
||||
|
||||
.. sidebar:: Contents
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
**IMPORTANT: As of Akka 1.1, Akka Future, Promise and DefaultPromise have all the functionality of DataFlowVariables, they also support non-blocking composition and advanced features like fold and reduce, Akka DataFlowVariable is therefor deprecated and will probably resurface in the following release as a DSL on top of Futures.**
|
||||
|
||||
Akka implements `Oz-style dataflow concurrency <http://www.mozart-oz.org/documentation/tutorial/node8.html#chapter.concurrency>`_ through dataflow (single assignment) variables and lightweight (event-based) processes/threads.
|
||||
|
||||
Dataflow concurrency is deterministic. This means that it will always behave the same. If you run it once and it yields output 5 then it will do that **every time**, run it 10 million times, same result. If it on the other hand deadlocks the first time you run it, then it will deadlock **every single time** you run it. Also, there is **no difference** between sequential code and concurrent code. These properties makes it very easy to reason about concurrency. The limitation is that the code needs to be side-effect free, e.g. deterministic. You can't use exceptions, time, random etc., but need to treat the part of your program that uses dataflow concurrency as a pure function with input and output.
|
||||
|
||||
The best way to learn how to program with dataflow variables is to read the fantastic book `Concepts, Techniques, and Models of Computer Programming <http://www.info.ucl.ac.be/%7Epvr/book.html>`_. By Peter Van Roy and Seif Haridi.
|
||||
|
||||
The documentation is not as complete as it should be, something we will improve shortly. For now, besides above listed resources on dataflow concurrency, I recommend you to read the documentation for the GPars implementation, which is heavily influenced by the Akka implementation:
|
||||
|
||||
* `<http://gpars.codehaus.org/Dataflow>`_
|
||||
* `<http://www.gpars.org/guide/guide/7.%20Dataflow%20Concurrency.html>`_
|
||||
|
||||
Dataflow Variables
|
||||
------------------
|
||||
|
||||
Dataflow Variable defines three different operations:
|
||||
|
||||
1. Define a Dataflow Variable
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
import static akka.dataflow.DataFlow.*;
|
||||
|
||||
DataFlowVariable<int> x = new DataFlowVariable<int>();
|
||||
|
||||
2. Wait for Dataflow Variable to be bound
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
x.get();
|
||||
|
||||
3. Bind Dataflow Variable
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
x.set(3);
|
||||
|
||||
A Dataflow Variable can only be bound once. Subsequent attempts to bind the variable will throw an exception.
|
||||
|
||||
You can also shutdown a dataflow variable like this:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
x.shutdown();
|
||||
|
||||
Threads
|
||||
-------
|
||||
|
||||
You can easily create millions lightweight (event-driven) threads on a regular workstation.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
import static akka.dataflow.DataFlow.*;
|
||||
import akka.japi.Effect;
|
||||
|
||||
thread(new Effect() {
|
||||
public void apply() { ... }
|
||||
});
|
||||
|
||||
You can also set the thread to a reference to be able to control its life-cycle:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
import static akka.dataflow.DataFlow.*;
|
||||
import akka.japi.Effect;
|
||||
|
||||
ActorRef t = thread(new Effect() {
|
||||
public void apply() { ... }
|
||||
});
|
||||
|
||||
... // time passes
|
||||
|
||||
t.tell(new Exit()); // shut down the thread
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Most of these examples are taken from the `Oz wikipedia page <http://en.wikipedia.org/wiki/Oz_%28programming_language%29>`_
|
||||
|
||||
Simple DataFlowVariable example
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This example is from Oz wikipedia page: http://en.wikipedia.org/wiki/Oz_(programming_language).
|
||||
Sort of the "Hello World" of dataflow concurrency.
|
||||
|
||||
Example in Oz:
|
||||
|
||||
.. code-block:: ruby
|
||||
|
||||
thread
|
||||
Z = X+Y % will wait until both X and Y are bound to a value.
|
||||
{Browse Z} % shows the value of Z.
|
||||
end
|
||||
thread X = 40 end
|
||||
thread Y = 2 end
|
||||
|
||||
Example in Akka:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
import static akka.dataflow.DataFlow.*;
|
||||
import akka.japi.Effect;
|
||||
|
||||
DataFlowVariable<int> x = new DataFlowVariable<int>();
|
||||
DataFlowVariable<int> y = new DataFlowVariable<int>();
|
||||
DataFlowVariable<int> z = new DataFlowVariable<int>();
|
||||
|
||||
thread(new Effect() {
|
||||
public void apply() {
|
||||
z.set(x.get() + y.get());
|
||||
System.out.println("z = " + z.get());
|
||||
}
|
||||
});
|
||||
|
||||
thread(new Effect() {
|
||||
public void apply() {
|
||||
x.set(40);
|
||||
}
|
||||
});
|
||||
|
||||
thread(new Effect() {
|
||||
public void apply() {
|
||||
y.set(40);
|
||||
}
|
||||
});
|
||||
|
||||
Example on life-cycle management of DataFlowVariables
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Shows how to shutdown dataflow variables and bind threads to values to be able to interact with them (exit etc.).
|
||||
|
||||
Example in Akka:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
import static akka.dataflow.DataFlow.*;
|
||||
import akka.japi.Effect;
|
||||
|
||||
// create four 'int' data flow variables
|
||||
DataFlowVariable<int> x = new DataFlowVariable<int>();
|
||||
DataFlowVariable<int> y = new DataFlowVariable<int>();
|
||||
DataFlowVariable<int> z = new DataFlowVariable<int>();
|
||||
DataFlowVariable<int> v = new DataFlowVariable<int>();
|
||||
|
||||
ActorRef main = thread(new Effect() {
|
||||
public void apply() {
|
||||
System.out.println("Thread 'main'")
|
||||
if (x.get() > y.get()) {
|
||||
z.set(x);
|
||||
System.out.println("'z' set to 'x': " + z.get());
|
||||
} else {
|
||||
z.set(y);
|
||||
System.out.println("'z' set to 'y': " + z.get());
|
||||
}
|
||||
|
||||
// main completed, shut down the data flow variables
|
||||
x.shutdown();
|
||||
y.shutdown();
|
||||
z.shutdown();
|
||||
v.shutdown();
|
||||
}
|
||||
});
|
||||
|
||||
ActorRef setY = thread(new Effect() {
|
||||
public void apply() {
|
||||
System.out.println("Thread 'setY', sleeping...");
|
||||
Thread.sleep(5000);
|
||||
y.set(2);
|
||||
System.out.println("'y' set to: " + y.get());
|
||||
}
|
||||
});
|
||||
|
||||
ActorRef setV = thread(new Effect() {
|
||||
public void apply() {
|
||||
System.out.println("Thread 'setV'");
|
||||
y.set(2);
|
||||
System.out.println("'v' set to y: " + v.get());
|
||||
}
|
||||
});
|
||||
|
||||
// shut down the threads
|
||||
main.tell(new Exit());
|
||||
setY.tell(new Exit());
|
||||
setV.tell(new Exit());
|
||||
|
|
@ -7,204 +7,167 @@ Dispatchers (Java)
|
|||
|
||||
.. contents:: :local:
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
An Akka ``MessageDispatcher`` is what makes Akka Actors "tick", it is the engine of the machine so to speak.
|
||||
All ``MessageDispatcher`` implementations are also an ``ExecutionContext``, which means that they can be used
|
||||
to execute arbitrary code, for instance :ref:`futures-java`.
|
||||
|
||||
Default dispatcher
|
||||
------------------
|
||||
|
||||
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`.
|
||||
Every ``ActorSystem`` will have a default dispatcher that will be used in case nothing else is configured for an ``Actor``.
|
||||
The default dispatcher can be configured, and is by default a ``Dispatcher`` with a "fork-join-executor", which gives excellent performance in most cases.
|
||||
|
||||
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.
|
||||
See below for details on which ones are available and how they can be configured.
|
||||
Setting the dispatcher for an Actor
|
||||
-----------------------------------
|
||||
|
||||
.. warning::
|
||||
Try to stick to a sensible default dispatcher, that means avoid using CallingThreadDispatcher, BalancingDispatcher or PinnedDispatcher
|
||||
as the default-dispatcher. This is because they have very specific requirements from the environment in which they are used.
|
||||
So in case you want to give your ``Actor`` a different dispatcher than the default, you need to do two things, of which the first is:
|
||||
|
||||
Setting the dispatcher
|
||||
----------------------
|
||||
.. includecode:: ../java/code/akka/docs/dispatcher/DispatcherDocTestBase.java#defining-dispatcher
|
||||
|
||||
You specify the id of the dispatcher to use when creating an actor. The id corresponds to the :ref:`configuration` key
|
||||
of the dispatcher settings.
|
||||
.. note::
|
||||
The "dispatcherId" you specify in withDispatcher is in fact a path into your configuration.
|
||||
So in this example it's a top-level section, but you could for instance put it as a sub-section,
|
||||
where you'd use periods to denote sub-sections, like this: ``"foo.bar.my-dispatcher"``
|
||||
|
||||
.. includecode:: code/akka/docs/dispatcher/DispatcherDocTestBase.java
|
||||
:include: imports,defining-dispatcher
|
||||
And then you just need to configure that dispatcher in your configuration:
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-dispatcher-config
|
||||
|
||||
And here's another example that uses the "thread-pool-executor":
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-thread-pool-dispatcher-config
|
||||
|
||||
For more options, see the default-dispatcher section of the :ref:`configuration`.
|
||||
|
||||
Types of dispatchers
|
||||
--------------------
|
||||
|
||||
There are 4 different types of message dispatchers:
|
||||
|
||||
* Thread-based (Pinned)
|
||||
* Event-based
|
||||
* Priority event-based
|
||||
* Work-sharing (Balancing)
|
||||
* Dispatcher
|
||||
|
||||
It is recommended to define the dispatcher in :ref:`configuration` to allow for tuning for different environments.
|
||||
- Sharability: Unlimited
|
||||
|
||||
Example of a custom event-based dispatcher, which can be used with
|
||||
``new Props().withCreator(MyUntypedActor.class).withDispatcher("my-dispatcher")``
|
||||
as in the example above:
|
||||
- Mailboxes: Any, creates one per Actor
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-dispatcher-config
|
||||
- Use cases: Default dispatcher, Bulkheading
|
||||
|
||||
Default values are taken from ``default-dispatcher``, i.e. all options doesn't need to be defined. See
|
||||
:ref:`configuration` for the default values of the ``default-dispatcher``. You can also override
|
||||
the values for the ``default-dispatcher`` in your configuration.
|
||||
- Driven by: ``java.util.concurrent.ExecutorService``
|
||||
specify using "executor" using "fork-join-executor",
|
||||
"thread-pool-executor" or the FQCN of
|
||||
an ``akka.dispatcher.ExecutorServiceConfigurator``
|
||||
|
||||
.. note::
|
||||
* PinnedDispatcher
|
||||
|
||||
It should be noted that the ``dispatcher-id`` used in :class:`Props` is in
|
||||
fact an absolute path into the configuration object, i.e. you can declare a
|
||||
dispatcher configuration nested within other configuration objects and refer
|
||||
to it like so: ``"my.config.object.myAwesomeDispatcher"``
|
||||
- Sharability: None
|
||||
|
||||
There are two different executor services:
|
||||
- Mailboxes: Any, creates one per Actor
|
||||
|
||||
* executor = "fork-join-executor", ``ExecutorService`` based on ForkJoinPool (jsr166y). This is used by default for
|
||||
``default-dispatcher``.
|
||||
* executor = "thread-pool-executor", ``ExecutorService`` based on ``java.util.concurrent.ThreadPoolExecutor``.
|
||||
- Use cases: Bulkheading
|
||||
|
||||
Note that the pool size is configured differently for the two executor services. The configuration above
|
||||
is an example for ``fork-join-executor``. Below is an example for ``thread-pool-executor``:
|
||||
- Driven by: Any ``akka.dispatch.ThreadPoolExecutorConfigurator``
|
||||
by default a "thread-pool-executor"
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-thread-pool-dispatcher-config
|
||||
* BalancingDispatcher
|
||||
|
||||
Let's now walk through the different dispatchers in more detail.
|
||||
- Sharability: Actors of the same type only
|
||||
|
||||
Thread-based
|
||||
^^^^^^^^^^^^
|
||||
- Mailboxes: Any, creates one for all Actors
|
||||
|
||||
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
|
||||
this dispatcher is that Actors do not block threads for each other.
|
||||
- Use cases: Work-sharing
|
||||
|
||||
The ``PinnedDispatcher`` is configured like this:
|
||||
- Driven by: ``java.util.concurrent.ExecutorService``
|
||||
specify using "executor" using "fork-join-executor",
|
||||
"thread-pool-executor" or the FQCN of
|
||||
an ``akka.dispatcher.ExecutorServiceConfigurator``
|
||||
|
||||
* CallingThreadDispatcher
|
||||
|
||||
- Sharability: Unlimited
|
||||
|
||||
- Mailboxes: Any, creates one per Actor per Thread (on demand)
|
||||
|
||||
- Use cases: Testing
|
||||
|
||||
- Driven by: The calling thread (duh)
|
||||
|
||||
More dispatcher configuration examples
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Configuring a ``PinnedDispatcher``:
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-pinned-dispatcher-config
|
||||
|
||||
Note that it must be used with ``executor = "thread-pool-executor"``.
|
||||
And then using it:
|
||||
|
||||
Event-based
|
||||
^^^^^^^^^^^
|
||||
.. includecode:: ../java/code/akka/docs/dispatcher/DispatcherDocTestBase.java#defining-pinned-dispatcher
|
||||
|
||||
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
|
||||
and supports a fluent configuration API to configure the ``BlockingQueue`` (type of queue, max items etc.) as well as the thread pool.
|
||||
Mailboxes
|
||||
---------
|
||||
|
||||
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
|
||||
design and implement your system in the most efficient way in regards to performance, throughput and latency.
|
||||
An Akka ``Mailbox`` holds the messages that are destined for an ``Actor``.
|
||||
Normally each ``Actor`` has its own mailbox, but with example a ``BalancingDispatcher`` all actors with the same ``BalancingDispatcher`` will share a single instance.
|
||||
|
||||
It comes with many different predefined BlockingQueue configurations:
|
||||
Builtin implementations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* 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>`_
|
||||
Akka comes shipped with a number of default mailbox implementations:
|
||||
|
||||
When using a bounded queue and it has grown up to limit defined the message processing will run in the caller's
|
||||
thread as a way to slow him down and balance producer/consumer.
|
||||
* UnboundedMailbox
|
||||
|
||||
Here is an example of a bounded mailbox:
|
||||
- Backed by a ``java.util.concurrent.ConcurrentLinkedQueue``
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-bounded-config
|
||||
- Blocking: No
|
||||
|
||||
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
|
||||
dispatcher will batch process up to ``throughput`` messages together when
|
||||
having elected an actor to run. 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 value (5) defined for ``default-dispatcher`` in the :ref:`configuration`.
|
||||
- Bounded: No
|
||||
|
||||
Browse the `ScalaDoc <scaladoc>`_ or look at the code for all the options available.
|
||||
* BoundedMailbox
|
||||
|
||||
Priority event-based
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
- Backed by a ``java.util.concurrent.LinkedBlockingQueue``
|
||||
|
||||
Sometimes it's useful to be able to specify priority order of messages, that is done by using Dispatcher and supply
|
||||
an UnboundedPriorityMailbox or BoundedPriorityMailbox with a ``java.util.Comparator[Envelope]`` or use a
|
||||
``akka.dispatch.PriorityGenerator`` (recommended).
|
||||
- Blocking: Yes
|
||||
|
||||
Creating a Dispatcher with a mailbox using PriorityGenerator:
|
||||
- Bounded: Yes
|
||||
|
||||
Config:
|
||||
* UnboundedPriorityMailbox
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala
|
||||
:include: prio-dispatcher-config-java
|
||||
- Backed by a ``java.util.concurrent.PriorityBlockingQueue``
|
||||
|
||||
Priority mailbox:
|
||||
- Blocking: Yes
|
||||
|
||||
.. includecode:: code/akka/docs/dispatcher/DispatcherDocTestBase.java
|
||||
:include: imports-prio-mailbox,prio-mailbox
|
||||
- Bounded: No
|
||||
|
||||
Usage:
|
||||
* BoundedPriorityMailbox
|
||||
|
||||
.. includecode:: code/akka/docs/dispatcher/DispatcherDocTestBase.java
|
||||
:include: imports-prio,prio-dispatcher
|
||||
- Backed by a ``java.util.PriorityBlockingQueue`` wrapped in an ``akka.util.BoundedBlockingQueue``
|
||||
|
||||
- Blocking: Yes
|
||||
|
||||
Work-sharing event-based
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Bounded: Yes
|
||||
|
||||
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.
|
||||
Although the technique used in this implementation is commonly known as "work stealing", the actual implementation is probably
|
||||
best described as "work donating" because the actor of which work is being stolen takes the initiative.
|
||||
This can be a great way to improve throughput at the cost of a little higher latency.
|
||||
* Durable mailboxes, see :ref:`durable-mailboxes`.
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-balancing-config
|
||||
Mailbox configuration examples
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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/>`_
|
||||
How to create a PriorityMailbox:
|
||||
|
||||
Making the Actor mailbox bounded
|
||||
--------------------------------
|
||||
.. includecode:: ../java/code/akka/docs/dispatcher/DispatcherDocTestBase.java#prio-mailbox
|
||||
|
||||
Global configuration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
And then add it to the configuration:
|
||||
|
||||
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,
|
||||
if not specified otherwise.
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#prio-dispatcher-config
|
||||
|
||||
.. code-block:: ruby
|
||||
And then an example on how you would use it:
|
||||
|
||||
akka {
|
||||
actor {
|
||||
default-dispatcher {
|
||||
# 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
|
||||
mailbox-capacity = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
.. includecode:: ../java/code/akka/docs/dispatcher/DispatcherDocTestBase.java#prio-dispatcher
|
||||
|
||||
Per-instance based configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. note::
|
||||
|
||||
You can also do it on a specific dispatcher instance.
|
||||
|
||||
.. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#my-bounded-config
|
||||
|
||||
|
||||
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.
|
||||
Make sure to include a constructor which takes
|
||||
``akka.actor.ActorSystem.Settings`` and ``com.typesafe.config.Config``
|
||||
arguments, as this constructor is invoked reflectively to construct your
|
||||
mailbox type. The config passed in as second argument is that section from
|
||||
the configuration which describes the dispatcher using this mailbox type; the
|
||||
mailbox type will be instantiated once for each dispatcher using it.
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ Java API
|
|||
event-bus
|
||||
scheduler
|
||||
futures
|
||||
dataflow
|
||||
fault-tolerance
|
||||
dispatchers
|
||||
routing
|
||||
|
|
|
|||
|
|
@ -180,3 +180,9 @@ By having your Typed Actor implementation class implement any and all of the fol
|
|||
* ``TypedActor.PostRestart``
|
||||
|
||||
You can hook into the lifecycle of your Typed Actor.
|
||||
|
||||
Proxying
|
||||
--------
|
||||
|
||||
You can use the ``typedActorOf`` that takes a TypedProps and an ActorRef to proxy the given ActorRef as a TypedActor.
|
||||
This is usable if you want to communicate remotely with TypedActors on other machines, just look them up with ``actorFor`` and pass the ``ActorRef`` to ``typedActorOf``.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue