matthewrk
matthewrk

Reputation: 687

Simple concurrency with an Akka Hello World sample

I'm evaluating Akka for a distributed service layer, the following example prints Hello {n} 10 times, but does it one after the other. As I understand it this is intentional for an Akka actor, so where do I go from here to make it concurrent?

import akka.actor._

object HelloActor {
  case class SayHello(message: String)
}

class HelloActor extends Actor {
  def receive = {
    case HelloActor.SayHello(message) =>
      Thread.sleep(1000)
      println(message)
  }
}

object Main extends App {
  val system = ActorSystem("ActorSystem")

  val hello = system.actorOf(Props[HelloActor])

  for (i <- 1 to 10) {
    hello ! HelloActor.SayHello(s"Hello $i")
  }
}

I've experimented with creating multiple actors from the Main class but that feels wrong somehow, shouldn't I just call the actor then it handles concurrency / spawning more actors on its own? Could anyone provide an example of this (preferably modifying the above code). I've been reading and reading but it feels like a lot to take in immediately and I feel I'm just missing a key concept here somewhere.

Upvotes: 6

Views: 2514

Answers (2)

sourcedelica
sourcedelica

Reputation: 24040

For your use case you'll probably want to use Routers.

For example:

val hello = system.actorOf(Props[HelloActor].withRouter(
  RoundRobinRouter(nrOfInstances = 10)))

hello ! HelloActor.SayHello("Hello!")   // Sends to one of the 10

As a side note, you should avoid blocking (ie. Thread.sleep) in your actor's receive method.

Upvotes: 4

cmbaxter
cmbaxter

Reputation: 35443

As @sourcedelica mentioned in the comments, routing is probably what you want to do. A simple refactor to your example using a RoundRobinRouter could look like this:

import akka.actor._
import akka.routing._

object HelloActor {
  case class SayHello
}

class HelloActor extends Actor {
  def receive = {
    case HelloActor.SayHello =>      
      println(s"saying hello from: ${self.path}")
  }
}

object Main extends App {
  val system = ActorSystem("ActorSystem")

  val hello = system.actorOf(Props[HelloActor].withRouter(RoundRobinRouter(10)))

  for (i <- 1 to 10) {
    hello ! HelloActor.SayHello
  }
}

This is a pretty simple example as it's using a simple router (round robin) and it's non-resizing. You can do a lot more with the routers and I highly suggest reading up on them more at:

http://doc.akka.io/docs/akka/2.2.3/scala/routing.html

Upvotes: 1

Related Questions