Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Scala actors process multiple messages simultaneously?

The reply to a recent question of mine indicated that an actor processed its messages one at a time. Is this true? I see nothing that explicitly says that (in Programming in Scala), which contains the following snippet (pp. 593)

If [the react method] finds a message that can be handled, [it] will schedule the handling of that message for later execution and throw an exception

(Emphasis my own). Two related (and mutually exclusive) questions:

  1. Assuming an actor could process multiple messages simulatenously, how can I force an actor to process messages 1 at a time (if this is what I wish to do)? (using receive?)
  2. Assuming an actor processes messages one at a time, how would I best implement an actor which in fact could process messages concurrently

edit: doing a bit of testing seems to bear out that I am wrong and that actors are indeed sequential. So it's question #2 which I need answering

like image 203
oxbow_lakes Avatar asked Jun 17 '09 13:06

oxbow_lakes


People also ask

How do actors communicate in Akka?

Actors communicate using asynchronous messages. This ensures that the sender does not stick around waiting for their message to be processed by the recipient. Instead, the sender puts the message in the recipient's mailbox and is free to do other work.

What are Scala actors?

More specifically, in a Scala actor system, actors interact and share information, without any presupposition of sequentiality. The mechanism by which actors share information with one another, and task one another, is message passing.

Why use Akka actors?

Akka Actors The Actor Model provides a higher level of abstraction for writing concurrent and distributed systems. It alleviates the developer from having to deal with explicit locking and thread management, making it easier to write correct concurrent and parallel systems.

What is Akka framework Scala?

Akka is a toolkit for building highly concurrent, distributed, and resilient message-driven applications for Java and Scala.


2 Answers

Actors process one message at a time. The classic pattern to process multiple messages is to have one coordinator actor front for a pool of consumer actors. If you use react then the consumer pool can be large but will still only use a small number of JVM threads. Here's an example where I create a pool of 10 consumers and one coordinator to front for them.

import scala.actors.Actor import scala.actors.Actor._  case class Request(sender : Actor, payload : String) case class Ready(sender : Actor) case class Result(result : String) case object Stop  def consumer(n : Int) = actor {   loop {     react {       case Ready(sender) =>          sender ! Ready(self)       case Request(sender, payload) =>         println("request to consumer " + n + " with " + payload)         // some silly computation so the process takes awhile         val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString         sender ! Result(result)         println("consumer " + n + " is done processing " + result )       case Stop => exit     }   } }  // a pool of 10 consumers val consumers = for (n <- 0 to 10) yield consumer(n)  val coordinator = actor {   loop {      react {         case msg @ Request(sender, payload) =>            consumers foreach {_ ! Ready(self)}            react {               // send the request to the first available consumer               case Ready(consumer) => consumer ! msg            }          case Stop =>             consumers foreach {_ ! Stop}             exit      }   } }  // a little test loop - note that it's not doing anything with the results or telling the coordinator to stop for (i <- 0 to 1000) coordinator ! Request(self, i.toString) 

This code tests to see which consumer is available and sends a request to that consumer. Alternatives are to just randomly assign to consumers or to use a round robin scheduler.

Depending on what you are doing, you might be better served with Scala's Futures. For instance, if you don't really need actors then all of the above machinery could be written as

import scala.actors.Futures._  def transform(payload : String) = {         val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString   println("transformed " + payload + " to " + result )   result }  val results = for (i <- 0 to 1000) yield future(transform(i.toString)) 
like image 90
James Iry Avatar answered Oct 08 '22 18:10

James Iry


I think that the answer is that an Actor cannot handle messages aynchronously. If you have an Actor which should be listening to messages where these messages can be handled asynchronously, then it could be written like this:

val actor_ = actor {

  loop {
    react {
      case msg =>
        //create a new actor to execute the work. The framework can then 
        //manage the resources effectively
        actor {
          //do work here
        }
      }
    }
  }
like image 22
oxbow_lakes Avatar answered Oct 08 '22 19:10

oxbow_lakes