HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Is this Scala/Akka idiomatic and correct for Akka 2.1?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thisidiomaticscalaakkacorrectforand

Problem

I'm wondering if there is anything i'm overlooking in the code below. I've taken the Pi calculation example, simplified it and converted it to Akka 2.1.

More specifically, i use the ask pattern to replace the Listener actor.

So is this

  • A proper and valid conversion?



  • A reasonable approach?



  • And is there a better approach to waiting for a result from an optionally distributed parallel reduction of a collection? In other words, is this an Akka equivalent of collection.par.map(work).par.reduce(result) or is there a better way?



```
object Work extends App {
// This is just some collection of data to process (possibly remotely).
val collection = 1 to 10000
val start = System.currentTimeMillis
val system = ActorSystem(f"Work${start}%08x${hashCode}%04x")
// The collection is converted into a stream since it could
// potentially be huge.
val master = system.actorOf(Props(new Master(collection.toStream)), name = "master")

// This replaces what the Listener was doing, i think.
implicit val timeout = Timeout(12.seconds)
val result = Await.result(master ? Run, timeout.duration)
println(s"\n${result}")
system.shutdown()

sealed trait WorkMessage
case object Run extends WorkMessage
case class Work(start: Int) extends WorkMessage
case class Result(value: Double) extends WorkMessage

sealed trait ControlMessage
case class Complete(elapsed:Long) extends ControlMessage

class Worker extends Actor {
def doWork(element: Int): Double = {
print(s" ${element}")
return element.toDouble
}
def receive = {
case Work(element) ⇒
sender ! Result(doWork(element))
}
}

class Master(work: Seq[Int]) extends Actor {
val nrOfCPUs = Runtime.getRuntime().availableProcessors();
val nrOfWorkers = nrOfCPUs * 4
val workSize = work.size
var nrOfResults: Int = _
val workerRouter = context.actorOf(
Props[Worker].withRouter(RoundRobinRouter(nrOfWorkers)), name = "workerRouter")

var d

Solution

I'm not an akka expert but I did used akka in a project so these are just some of my observations:

-
result is blocking.

val result = Await.result(master ? Run, timeout.duration)


On case the master takes longer due to load or whatever, the pending result will
exceed the timeout. Try async ask directly.

val result ask(actor, msg).mapTo[String]


-
In order to remain async you may carry on with an onComplete as
Future callback:

result onComplete {
    case Success(result) => doSomethingOnSuccess(result)
    case Failure(failure) => doSomethingOnFailure(failure)
}


In this case no operation ever blocks the running thread. Read the Akka docs for more details


And is there a better approach to waiting for a result from an
optionally distributed parallel reduction of a collection? In other
words, is this an Akka equivalent of
collection.par.map(work).par.reduce(result) or is there a better way?

Operating on distributed data-sets is much better done on an in-memory data processing engine. Using the distributed word count as example, in Spark you do:

file.flatMap(line => line.split(" "))
    .map(word => (word, 1))
    .reduceByKey(_ + _)


Actors are made for message processing such as Twitter or WhatsApp but for computing tasks that must be fast, you use either MapReduce (Hadoop) for offline crunching of Spark/Storm for real-time processing. Hope that answers your question.

Code Snippets

val result = Await.result(master ? Run, timeout.duration)
val result ask(actor, msg).mapTo[String]
result onComplete {
    case Success(result) => doSomethingOnSuccess(result)
    case Failure(failure) => doSomethingOnFailure(failure)
}
file.flatMap(line => line.split(" "))
    .map(word => (word, 1))
    .reduceByKey(_ + _)

Context

StackExchange Code Review Q#21557, answer score: 3

Revisions (0)

No revisions yet.