Lately I have been investigating the awesome Akka framework to try to get a feel for it and decide if it would be right for my project. Currently this application is a plain old java application that performs some very complex calculations by making calls to various external c++ executable's (sometimes the calculations can take hours to run). In code it would look something like this
public static class Worker extends UntypedActor {
// Run Very Long Process
public void onReceive(Object message) {
if (message instanceof Work) {
Work work = (Work) message;
double result = veryLongProcess(work.getStart(),work.getNrOfElements());
getSender().tell(new Result(result), getSelf());
} else {
unhandled(message);
}
}
}
My question is can Akka handle actors taking sometimes hours to return from their execution?
Answering your question directly; there is a good article on this very topic:
Again, if you have long-running computations, having them run in a separate ExecutionContext for CPU-bound tasks is a good idea.
The article has the following example:
import java.util.concurrent.Executors
import concurrent.ExecutionContext
//I added 'private' for the rest of the example
private val executorService = Executors.newFixedThreadPool(4)
private val executionContext = ExecutionContext.fromExecutorService(executorService)
Answering indirectly,
Futures First
I completely agree that Akka Actors are a very useful tool for particular types of work. When it comes to caching, Actors
& Agents
are the best game in town.
However, in this instance I would suggest leveraging a Future
instead of an Actor. You could make veryLongProcess a private
function. The privacy would allow complete control over the number of threads calling the method at once:
def longProcessFut(start : Int, noOfElements : Int) : Future[Result] = Future {
veryLongProcess(start, noOfElements)
}(executionContext)//controls the executing pool of veryLongProcess
Simple, concise, and asynchronous.
No killing of letters, no overloaded receive method that accepts anything under the sun, nor Props, not even an ActorRef was necessary for the Future. Bloat, beer belly I say!
Besides, your user is going to create a Future no matter what because of ?
:
//Actor user code, too verbose
val longProcessRef = actorSystem actorOf Props[Worker]
val fut : Future[Result] = (longProcessRef ? Work(0,42)).mapTo[Result]
Compared to using Futures directly
//happy user code
val fut : Future[Result] = longProcessFut(0, 42)
Same great Future, but half the calories!
You can control the dispatcher of the Future in the same manner(s) as suggested in the comments, which are quite good. You can even use actorSystem.dispatcher
as your Future dispatcher to control the dispatcher behavior.
If the long running business logic / algorithm is incremental, produces intermediate results and/or can run for a very long time then you may want to reuse excellent design snippets from here: Incremental processing in an akka actor
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With