Can Scala actors process multiple messages simultaneously?

后端 未结 4 1068
面向向阳花
面向向阳花 2020-12-02 07:03

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 P

相关标签:
4条回答
  • 2020-12-02 07:51

    If you want to do multiple things then you should be using multiple actors. The whole reason to use actors is to divide up the work among multiple independent processes.

    0 讨论(0)
  • 2020-12-02 07:57

    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))
    
    0 讨论(0)
  • 2020-12-02 08:00

    You can try using the Futures concepts. Please store all these messages using Futures and then try processing those all.

    0 讨论(0)
  • 2020-12-02 08:02

    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
            }
          }
        }
      }
    
    0 讨论(0)
提交回复
热议问题