Pregunta

La respuesta a una pregunta reciente mía indicó que un actor procesó sus mensajes uno a la vez . ¿Es esto cierto? No veo nada que diga explícitamente eso (en Programación en Scala ), que contiene el siguiente fragmento (pp. 593)

  

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

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

  1. Suponiendo que un actor pueda procesar múltiples mensajes de manera simulada, ¿cómo puedo obligar a un actor a procesar los mensajes 1 a la vez (si esto es lo que deseo hacer)? (usando recibir ?)
  2. Suponiendo que un actor procesa los mensajes uno a la vez, ¿cómo podría implementar mejor un actor que, de hecho, podría procesar mensajes simultáneamente

editar: hacer un poco de prueba parece confirmar que estoy equivocado y que los actores son secuenciales. Entonces es la pregunta # 2 que necesito responder

¿Fue útil?

Solución

Los actores procesan un mensaje a la vez. El patrón clásico para procesar múltiples mensajes es tener un coordinador de frente de actor para un grupo de actores de consumo. Si usa reaccionar, el grupo de consumidores puede ser grande pero solo usará una pequeña cantidad de subprocesos JVM. Aquí hay un ejemplo en el que creo un grupo de 10 consumidores y un coordinador para que los presente.

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)

Este código prueba para ver qué consumidor está disponible y envía una solicitud a ese consumidor. Las alternativas son simplemente asignar aleatoriamente a los consumidores o utilizar un programador de turnos.

Dependiendo de lo que esté haciendo, podría ser mejor servido con Scala's Futures. Por ejemplo, si realmente no necesita actores, 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))

Otros consejos

Creo que la respuesta es que un Actor no puede manejar los mensajes de forma asíncrona. Si tiene un Actor que debería estar escuchando mensajes donde estos mensajes pueden manejarse de forma asíncrona , entonces podría escribirse 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
        }
      }
    }
  }

Si quieres hacer varias cosas, entonces deberías estar usando múltiples actores. Toda la razón para usar actores es dividir el trabajo entre múltiples procesos independientes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top