DOC: Improved Pi example. Removed latch and return result to listener actor. See #1729
This commit is contained in:
parent
5f4d566a8c
commit
c64b73004a
2 changed files with 46 additions and 42 deletions
|
|
@ -262,7 +262,7 @@ computation, creating a set of ``Worker`` actors. Then it splits up the work
|
|||
into discrete chunks, and sends these chunks to the different workers in a
|
||||
round-robin fashion. The master waits until all the workers have completed their
|
||||
work and sent back results for aggregation. When computation is completed the
|
||||
master prints out the result, shuts down all workers and then itself.
|
||||
master sends the result to the ``Listener``, which prints out the result.
|
||||
|
||||
With this in mind, let's now create the messages that we want to have flowing in
|
||||
the system. We need three different messages:
|
||||
|
|
@ -272,6 +272,9 @@ the system. We need three different messages:
|
|||
the work assignment
|
||||
- ``Result`` -- sent from the ``Worker`` actors to the ``Master`` actor
|
||||
containing the result from the worker's calculation
|
||||
- ``PiEstimate`` -- sent from the ``Master`` actor to the
|
||||
``Listener`` actor containing the the final pi result and how long time
|
||||
the calculation took
|
||||
|
||||
Messages sent to actors should always be immutable to avoid sharing mutable
|
||||
state. In scala we have 'case classes' which make excellent messages. So let's
|
||||
|
|
@ -330,19 +333,8 @@ Here is the master actor:
|
|||
|
||||
A couple of things are worth explaining further.
|
||||
|
||||
First, we are passing in a ``java.util.concurrent.CountDownLatch`` to the
|
||||
``Master`` actor. This latch is only used for plumbing (in this specific
|
||||
tutorial), to have a simple way of letting the outside world knowing when the
|
||||
master can deliver the result and shut down. In more idiomatic Akka code
|
||||
we would not use a latch but other abstractions and functions like ``Future``
|
||||
and ``?`` to achieve the same thing in a non-blocking way.
|
||||
But for simplicity let's stick to a ``CountDownLatch`` for now.
|
||||
|
||||
Second, we are adding a couple of life-cycle callback methods; ``preStart`` and
|
||||
``postStop``. In the ``preStart`` callback we are recording the time when the
|
||||
actor is started and in the ``postStop`` callback we are printing out the result
|
||||
(the approximation of Pi) and the time it took to calculate it. In this call we
|
||||
also invoke ``latch.countDown()`` to tell the outside world that we are done.
|
||||
Note that we are passing in a ``ActorRef`` to the ``Master`` actor. This is used to
|
||||
report the the final result to the outside world.
|
||||
|
||||
But we are not done yet. We are missing the message handler for the ``Master``
|
||||
actor. This message handler needs to be able to react to two different messages:
|
||||
|
|
@ -355,7 +347,8 @@ The ``Calculate`` handler is sending out work to all the ``Worker`` via its rout
|
|||
The ``Result`` handler gets the value from the ``Result`` message and aggregates it to
|
||||
our ``pi`` member variable. We also keep track of how many results we have received back,
|
||||
and if that matches the number of tasks sent out, the ``Master`` actor considers itself done and
|
||||
invokes the ``self.stop()`` method to stop itself *and* all its supervised actors.
|
||||
sends the final result to the ``listener``. When done it also invokes the ``context.stop(self)``
|
||||
method to stop itself *and* all its supervised actors.
|
||||
In this case it has one supervised actor, the router, and this in turn has ``nrOfWorkers`` supervised actors.
|
||||
All of them will be stopped automatically as the invocation of any supervisor's ``stop`` method
|
||||
will propagate down to all its supervised 'children'.
|
||||
|
|
@ -365,6 +358,14 @@ Let's capture this in code:
|
|||
.. includecode:: ../../akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala#master-receive
|
||||
|
||||
|
||||
Creating the result listener
|
||||
============================
|
||||
|
||||
The listener is straightforward. When it receives the ``PiEstimate`` from the ``Master`` it
|
||||
prints the result and shuts down the ``ActorSystem``.
|
||||
|
||||
.. includecode:: ../../akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala#result-listener
|
||||
|
||||
Bootstrap the calculation
|
||||
=========================
|
||||
|
||||
|
|
@ -380,9 +381,9 @@ start up the ``Master`` actor and wait for it to finish:
|
|||
.. includecode:: ../../akka-tutorials/akka-tutorial-first/src/main/scala/Pi.scala#app
|
||||
:exclude: actors-and-messages
|
||||
|
||||
As you can see the *calculate* method above it creates an ActorSystem and this is the Akka container which
|
||||
As you can see the *calculate* method above it creates an ``ActorSystem`` and this is the Akka container which
|
||||
will contain all actors created in that "context". An example of how to create actors in the container
|
||||
is the *'system.actorOf(...)'* line in the calculate method. In this case we create a top level actor.
|
||||
is the *'system.actorOf(...)'* line in the calculate method. In this case we create two top level actors.
|
||||
If you instead where in an actor context, i.e. inside an actor creating other actors, you should use
|
||||
*context.actorOf(...)*. This is illustrated in the Master code above.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue