Actores proceso de un mensaje a la vez. El patrón clásico para procesar mensajes múltiples es tener un frente de actor coordinador para un grupo de actores consumidores. Si usa reaccionar, el grupo de consumidores puede ser grande pero solo usará una pequeña cantidad de subprocesos de JVM. Aquí hay un ejemplo en el que creo un grupo de 10 consumidores y un coordinador para ellos.
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)
pruebas de este código para ver lo que el consumidor está disponible y envía una solicitud a ese consumidor. Las alternativas son simplemente asignar aleatoriamente a los consumidores o utilizar un programador round robin.
Dependiendo de lo que esté haciendo, es mejor que se lo atienda con Scala's Futures. Por ejemplo, si realmente no necesita actores, entonces toda la maquinaria anterior podría escribirse como
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))
Realmente no veo cómo esta pregunta justifica un voto a la baja. Si puedo leer un capítulo completo sobre actores en Programación en Scala y no estoy seguro de la respuesta, es una pregunta completamente válida. –
Un solo actor procesa los mensajes secuencialmente porque la idea es que uno puede usar un actor para mediar en el acceso a un recurso compartido (por lo demás), y no se requerirá ninguna otra sincronización en el recurso compartido.Si los mensajes se pueden procesar de forma secuencial, deberá usar bloqueos dentro de los actores para garantizar que no se produzcan errores de sincronización. –