There is a bug somewhere in the code below (trying recursion with Akka). Algorithm stops and the process (Java Application) is executed forever in JVM unless I kill it from the System Monitor. I believe it should be a very simple hack to fix it.
Here is an example on how to use Akka for parallel Pi approximation. Below is an attempt to show how Akka works with recursive Actors. So the master creates 2 workers, sends them the same message to decrement some int value. They do that in parallel and check if the integer value is not equal to 0. If so, they return the result integer value (0) to the master or they both create again 2 workers and send them a recently decremented value.. If the depth of this tree is greater than 1 (the integer was of >1 value) then workers send their results to the workers that called them and only in the end to the master. Well, it is really easy as below (Decrement, NewIntValue and FinalIntValue are essentially the same, they have different names to make it more understandable):
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
import akka.routing.RoundRobinRouter;
public class StackOverFlow {
public static void main(String[] args) {
StackOverFlow rid = new StackOverFlow();
rid.start(2);
}
public void start(final int workersNumber) {
// create an Akka system
ActorSystem system = ActorSystem.create("IntDec");
// create the result listener, which will print the result and shutdown the system
final ActorRef listener = system.actorOf(new Props(Listener.class), "listener");
// create the master
ActorRef master = system.actorOf(new Props(new UntypedActorFactory() {
public UntypedActor create() {
return new Master(workersNumber, listener);
}
}), "master");
// start the computation
master.tell(new Compute());
}
static class Compute {}
static class Decrement {
private final int intValue;
public Decrement(int value) {
this.intValue = value;
}
public int getValue() {
return intValue;
}
}
static class NewIntValue {
private final int intValue;
public NewIntValue(int value) {
intValue = value;
}
public int getValue() {
return intValue;
}
}
static class FinalIntValue {
private final int intValue;
public FinalIntValue(int value) {
intValue = value;
}
public int getValue() {
return intValue;
}
}
public static class Worker extends UntypedActor {
private int resultsNumber = 0;
private final int messagesNumber = 2;
private final ActorRef workerRouter;
public Worker(final int workersNumber) {
workerRouter = getContext().actorOf(
new Props(new UntypedActorFactory() {
public UntypedActor create() {
return new Worker(workersNumber);
}
}).withRouter(
new RoundRobinRouter(workersNumber)
), "workerRouter");
}
public void onReceive(Object message) {
if (message instanceof Decrement) {
// get and decrement the int value
Decrement job = (Decrement) message;
int intValue = job.getValue();
System.out.println("\tWorker:Decrement " + intValue);
intValue--;
if (intValue == 0) {
// we are finished
getSender().tell(new NewIntValue(intValue), getSelf());
// stop this actor and all its supervised children
getContext().stop(getSelf());
} else {
for (int i = 0; i < messagesNumber; i++) {
// notify a worker
workerRouter.tell(new Decrement(intValue), getSelf());
}
}
} else if (message instanceof NewIntValue) {
NewIntValue newInt = (NewIntValue) message;
int intValue = newInt.getValue();
System.out.println("\tWorker:NewIntValue!!! " + intValue);
resultsNumber++;
if (resultsNumber == messagesNumber) {
// we are finished
getSender().tell(new NewIntValue(intValue), getSelf());
// stop this actor and all its supervised children
getContext().stop(getSelf());
}
} else unhandled(message);
}
}
public static class Master extends UntypedActor {
private int resultsNumber = 0;
private final int messagesNumber = 2;
private int intValue = 2;
private final ActorRef listener;
private final ActorRef workerRouter;
public Master(final int workersNumber, ActorRef listener) {
this.listener = listener;
workerRouter = getContext().actorOf(
new Props(new UntypedActorFactory() {
public UntypedActor create() {
return new Worker(workersNumber);
}
}).withRouter(
new RoundRobinRouter(workersNumber)
), "workerRouter");
}
public void onReceive(Object message) {
if (message instanceof Compute) {
System.out.println("\tMaster:Compute " + intValue);
System.out.println(
"\n\tInitial integer value: " + intValue);
for (int i = 0; i < messagesNumber; i++) {
workerRouter.tell(new Decrement(intValue), getSelf());
}
} else if (message instanceof NewIntValue) {
NewIntValue newInt = (NewIntValue) message;
intValue = newInt.getValue();
System.out.println("\tMaster:NewIntValue " + intValue);
resultsNumber++;
if (resultsNumber == messagesNumber) {
// send the result to the listener
listener.tell(new FinalIntValue(intValue), getSelf());
// stop this actor and all its supervised children
getContext().stop(getSelf());
}
} else unhandled(message);
}
}
public static class Listener extends UntypedActor {
public void onReceive(Object message) {
if (message instanceof FinalIntValue) {
FinalIntValue finalInt = (FinalIntValue) message;
System.out.println(
"\n\tFinal integer value: " + finalInt.getValue());
getContext().system().shutdown();
} else {
unhandled(message);
}
}
}
}
private ActorRef sender;to theWorkerclass;sender = getSender();at the beginning of theDecrementmessage;getSender()tosenderin theNewIntValuemethod of theWorkerclass;