incorporated feedback on the java tutorial

This commit is contained in:
Jonas Bonér 2011-04-20 09:24:19 +02:00
parent 90d6844b4a
commit 5e86f2ee81
4 changed files with 40 additions and 42 deletions

View file

@ -184,12 +184,6 @@ We also need to edit the ``pom.xml`` build file. Let's add the dependency we nee
</build>
</project>
So, now we are all set. Just one final thing to do; make Maven download the dependencies it needs. That can be done by invoking::
$ mvn package
Maven itself needs a whole bunch of dependencies but our project will only need one; ``akka-actor-1.1.jar``. Maven downloads that as well.
Start writing the code
----------------------
@ -235,15 +229,15 @@ Messages sent to actors should always be immutable to avoid sharing mutable stat
static class Calculate {}
static class Work {
private final int arg;
private final int start;
private final int nrOfElements;
public Work(int arg, int nrOfElements) {
this.arg = arg;
public Work(int start, int nrOfElements) {
this.start = start;
this.nrOfElements = nrOfElements;
}
public int getArg() { return arg; }
public int getStart() { return start; }
public int getNrOfElements() { return nrOfElements; }
}
@ -271,7 +265,7 @@ Now we can create the worker actor. This is done by extending in the ``UntypedA
Work work = (Work) message;
// perform the work
double result = calculatePiFor(work.getArg(), work.getNrOfElements())
double result = calculatePiFor(work.getStart(), work.getNrOfElements())
// reply with the result
getContext().replyUnsafe(new Result(result));
@ -285,10 +279,10 @@ As you can see we have now created an ``UntypedActor`` with a ``onReceive`` meth
The only thing missing in our ``Worker`` actor is the implementation on the ``calculatePiFor(..)`` method::
// define the work
private double calculatePiFor(int arg, int nrOfElements) {
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = arg * nrOfElements; i <= ((arg + 1) * nrOfElements - 1); i++) {
acc += 4 * Math.pow(-1, i) / (2 * i + 1);
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
@ -335,7 +329,7 @@ As you can see we are using the ``actorOf`` factory method to create actors, thi
import static akka.actor.Actors.actorOf;
In thing to note is that we used two different versions of the ``actorOf`` method. For creating the ``Worker`` actor we just pass in the class but to create the ``PiRouter`` actor we can't do that since the constructor in the ``PiRouter`` class takes arguments, instead we need to use the ``UntypedActorFactory`` which unfortunately is a bit more verbose.
One thing to note is that we used two different versions of the ``actorOf`` method. For creating the ``Worker`` actor we just pass in the class but to create the ``PiRouter`` actor we can't do that since the constructor in the ``PiRouter`` class takes arguments, instead we need to use the ``UntypedActorFactory`` which unfortunately is a bit more verbose.
``actorOf`` is the only way to create an instance of an Actor, this is enforced by Akka runtime. The ``actorOf`` method instantiates the actor and returns, not an instance to the actor, but an instance to an ``ActorRef``. This reference is the handle through which you communicate with the actor. It is immutable, serializable and location-aware meaning that it "remembers" its original actor even if it is sent to other nodes across the network and can be seen as the equivalent to the Erlang actor's PID.
@ -438,8 +432,8 @@ Let's capture this in code::
if (message instanceof Calculate) {
// schedule work
for (int arg = 0; arg < nrOfMessages; arg++) {
router.sendOneWay(new Work(arg, nrOfElements), getContext());
for (int start = 0; start < nrOfMessages; start++) {
router.sendOneWay(new Work(start, nrOfElements), getContext());
}
// send a PoisonPill to all workers telling them to shut down themselves
@ -525,15 +519,15 @@ Before we package it up and run it, let's take a look at the full code now, with
static class Calculate {}
static class Work {
private final int arg;
private final int start;
private final int nrOfElements;
public Work(int arg, int nrOfElements) {
this.arg = arg;
public Work(int start, int nrOfElements) {
this.start = start;
this.nrOfElements = nrOfElements;
}
public int getArg() { return arg; }
public int getStart() { return start; }
public int getNrOfElements() { return nrOfElements; }
}
@ -553,10 +547,10 @@ Before we package it up and run it, let's take a look at the full code now, with
static class Worker extends UntypedActor {
// define the work
private double calculatePiFor(int arg, int nrOfElements) {
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = arg * nrOfElements; i <= ((arg + 1) * nrOfElements - 1); i++) {
acc += 4 * Math.pow(-1, i) / (2 * i + 1);
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
@ -567,7 +561,7 @@ Before we package it up and run it, let's take a look at the full code now, with
Work work = (Work) message;
// perform the work
double result = calculatePiFor(work.getArg(), work.getNrOfElements())
double result = calculatePiFor(work.getStart(), work.getNrOfElements())
// reply with the result
getContext().replyUnsafe(new Result(result));
@ -628,8 +622,8 @@ Before we package it up and run it, let's take a look at the full code now, with
if (message instanceof Calculate) {
// schedule work
for (int arg = 0; arg < nrOfMessages; arg++) {
router.sendOneWay(new Work(arg, nrOfElements), getContext());
for (int start = 0; start < nrOfMessages; start++) {
router.sendOneWay(new Work(start, nrOfElements), getContext());
}
// send a PoisonPill to all workers telling them to shut down themselves
@ -716,7 +710,7 @@ When we have compiled the source file we are ready to run the application. This
Yippee! It is working.
If you have not defined an the ``AKKA_HOME`` environment variable then Akka can't find the ``akka.conf`` configuration file and will print out a ``Cant load akka.conf`` warning. This is ok since it will then just use the defaults.
If you have not defined the ``AKKA_HOME`` environment variable then Akka can't find the ``akka.conf`` configuration file and will print out a ``Cant load akka.conf`` warning. This is ok since it will then just use the defaults.
Run it inside Maven
-------------------
@ -741,6 +735,8 @@ Conclusion
We have learned how to create our first Akka project using Akka's actors to speed up a computation-intensive problem by scaling out on multi-core processors (also known as scaling up). We have also learned to compile and run an Akka project using either the tools on the command line or the SBT build system.
If you have a multi-core machine then I encourage you to try out different number of workers (number of working actors) by tweaking the ``nrOfWorkers`` variable to for example; 2, 4, 6, 8 etc. to see performance improvement by scaling up.
Now we are ready to take on more advanced problems. In the next tutorial we will build on this one, refactor it into more idiomatic Akka and Scala code, and introduce a few new concepts and abstractions. Whenever you feel ready, join me in the `Getting Started Tutorial: Second Chapter <TODO>`_.
Happy hakking.

View file

@ -238,7 +238,7 @@ The only thing missing in our ``Worker`` actor is the implementation on the ``ca
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
acc += 4 * math.pow(-1, i) / (2 * i + 1)
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@ -404,7 +404,7 @@ But before we package it up and run it, let's take a look at the full code now,
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
acc += 4 * math.pow(-1, i) / (2 * i + 1)
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}
@ -435,7 +435,7 @@ But before we package it up and run it, let's take a look at the full code now,
def receive = {
case Calculate =>
// schedule work
//for (arg <- 0 until nrOfMessages) router ! Work(arg, nrOfElements)
//for (start <- 0 until nrOfMessages) router ! Work(start, nrOfElements)
for (i <- 0 until nrOfMessages) router ! Work(i * nrOfElements, nrOfElements)
// send a PoisonPill to all workers telling them to shut down themselves
@ -535,6 +535,8 @@ Conclusion
We have learned how to create our first Akka project using Akka's actors to speed up a computation-intensive problem by scaling out on multi-core processors (also known as scaling up). We have also learned to compile and run an Akka project using either the tools on the command line or the SBT build system.
If you have a multi-core machine then I encourage you to try out different number of workers (number of working actors) by tweaking the ``nrOfWorkers`` variable to for example; 2, 4, 6, 8 etc. to see performance improvement by scaling up.
Now we are ready to take on more advanced problems. In the next tutorial we will build on this one, refactor it into more idiomatic Akka and Scala code, and introduce a few new concepts and abstractions. Whenever you feel ready, join me in the `Getting Started Tutorial: Second Chapter <TODO>`_.
Happy hakking.

View file

@ -56,15 +56,15 @@ public class Pi {
static class Calculate {}
static class Work {
private final int arg;
private final int start;
private final int nrOfElements;
public Work(int arg, int nrOfElements) {
this.arg = arg;
public Work(int start, int nrOfElements) {
this.start = start;
this.nrOfElements = nrOfElements;
}
public int getArg() { return arg; }
public int getStart() { return start; }
public int getNrOfElements() { return nrOfElements; }
}
@ -84,10 +84,10 @@ public class Pi {
static class Worker extends UntypedActor {
// define the work
private double calculatePiFor(int arg, int nrOfElements) {
private double calculatePiFor(int start, int nrOfElements) {
double acc = 0.0;
for (int i = arg * nrOfElements; i <= ((arg + 1) * nrOfElements - 1); i++) {
acc += 4 * Math.pow(-1, i) / (2 * i + 1);
for (int i = start * nrOfElements; i <= ((start + 1) * nrOfElements - 1); i++) {
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1);
}
return acc;
}
@ -98,7 +98,7 @@ public class Pi {
Work work = (Work) message;
// perform the work
double result = calculatePiFor(work.getArg(), work.getNrOfElements());
double result = calculatePiFor(work.getStart(), work.getNrOfElements());
// reply with the result
getContext().replyUnsafe(new Result(result));
@ -157,8 +157,8 @@ public class Pi {
if (message instanceof Calculate) {
// schedule work
for (int arg = 0; arg < nrOfMessages; arg++) {
router.sendOneWay(new Work(arg, nrOfElements), getContext());
for (int start = 0; start < nrOfMessages; start++) {
router.sendOneWay(new Work(start, nrOfElements), getContext());
}
// send a PoisonPill to all workers telling them to shut down themselves

View file

@ -59,7 +59,7 @@ object Pi extends App {
def calculatePiFor(start: Int, nrOfElements: Int): Double = {
var acc = 0.0
for (i <- start until (start + nrOfElements))
acc += 4 * math.pow(-1, i) / (2 * i + 1)
acc += 4 * (1 - (i % 2) * 2) / (2 * i + 1)
acc
}