2009-06-17 20 views
27

The reply a una reciente pregunta mía indicó que un actor procesó sus mensajes uno a la vez. ¿Es esto cierto? Veo nada que diga explícitamente que (en Programación en Scala), que contiene el siguiente fragmento (pp. 593)¿Pueden los actores de Scala procesar múltiples mensajes simultáneamente?

Si [el método react] encuentra un mensaje que puede ser manejado, [que] se programar el manejo de ese mensaje para su posterior ejecución y lanzar una excepción

(énfasis mío). Dos preguntas relacionadas (y mutuamente excluyentes):

  1. Suponiendo que un actor podría procesar múltiples mensajes simulatenously, ¿cómo puedo forzar un actor para procesar los mensajes 1 a la vez (si esto es lo que quiero hacer)? (Usando receive?)
  2. Suponiendo un actor procesa los mensajes de uno en uno, ¿cómo iba a implementar mejor actor que de hecho podía mensajes de proceso concurrente

edición: hacer un poco de las pruebas parece Afirmo que estoy equivocado y que los actores son realmente secuenciales. Por lo tanto, es la pregunta n. ° 2 a la que debo responder

+5

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. –

+0

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. –

Respuesta

26

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)) 
+0

¿Puede explicar lo que significa Ready? –

+0

Listo en este ejemplo es una clase de caso que actúa como un mensaje para pasar. El coordinador envía un mensaje de Listo al consumidor que básicamente significa '¿estás listo?' y el consumidor responde con un mensaje listo que significa 'sí'. El primer consumidor que responde se pasa la solicitud. – harmanjd

0

Si desea hacer varias cosas, entonces debe utilizar múltiples actores. La razón para usar actores es dividir el trabajo entre múltiples procesos independientes.

+0

Esta es una respuesta inútil. Digamos que tengo un actor que lee los eventos que se procesarán y los envía a otro actor para que los procese. Excepto que en realidad, múltiples eventos se pueden procesar simultáneamente, incluso si el código de procesamiento real es exactamente el mismo (que por lo tanto escribiría en un solo lugar, es decir, en 1 actor). ¿Cómo dejo que el marco de actores "replique" (o cree un grupo) de estos actores (idénticos) para que pueda hacer el mejor uso posible de mis recursos de programación? –

+0

Me refiero al "mejor uso de los recursos de mi procesador" –

+1

Mi respuesta no fue útil porque su pregunta no fue enmarcada correctamente. Un actor es un proceso, no una pieza de código. Al igual que un objeto es una instancia de una clase. No me preguntaste cómo creo múltiples actores para manejar múltiples mensajes. Querías saber cómo lograr que un actor procese múltiples mensajes simultáneamente. Mi respuesta fue un intento de aclarar lo que percibí como su incomprensión del modelo Actor. – mamboking

6

Creo que la respuesta es que Actor no puede manejar los mensajes de forma asincrónica. Si usted tiene una Actor que debería estar escuchando a los mensajes que estos mensajes pueden ser manejados de forma asíncrona, entonces podría ser escrita así:

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 
     } 
     } 
    } 
    } 
Cuestiones relacionadas