2011-04-05 11 views
37

En Akka, ¿hay alguna manera de restringir los mensajes a los actores para que sean de un tipo estático específico que no sea el uso de las API "Typed Actor" que utilizan un modelo de programación de estilo RPC?¿Cómo restringir los mensajes del actor a tipos específicos?

¿Puedo utilizar el estilo de pase de mensajes con Akka sin descartar la seguridad del tipo estático en los límites del actor?

Por ejemplo, me gustaría utilizar código como este:

sealed abstract class FooMessage 
case object Foo extends FooMessage 
case object Bar extends FooMessage 

class FooActor extends Actor[FooMessage] { 
    def receive = { 
    case Foo =>() // OK 

    // Would raise a compiler error: 
    // case s: String => error("Can't happen, String is not a subtype of FooMessage") 

    } 
} 

val fooActor = actorOf[FooActor] 
fooActor ! Foo // OK 

// Won't compile: 
fooActor ! "Hello" 

Tal vez habría que extender algún rasgo base o tener una construcción como Either para permitir mensajes de nivel de sistema (Exit, etc.)

Respuesta

25

entonces tendría para codificar el tipo de mensaje en el que el árbitro Actor, lo que disminuiría drásticamente el valor de algo como el ActorRegistry.

Además, con mecanismos potentes como "become" (que es fundamental para el modelo de actor) tipear los mensajes es menos valioso.

Dado que Akka no pierde memoria cuando un mensaje no coincide con el comportamiento actual, no existe el mismo riesgo de enviar los mensajes "incorrectos" al actor "incorrecto".

Además, los actores son dinámicos por naturaleza, así que si quieres hacerlos estáticos, usa TypedActor (que no es RPC, es solo como RPC como actores comunes, los métodos nulos son! Llamadas, el tipo de retorno futuro es !!! y otros tipos de devolución se basan en!)

La práctica común es declarar qué mensajes puede recibir un Actor en el objeto complementario del Actor, lo que hace que sea mucho más fácil saber qué puede recibir.

¿Eso ayuda?

+2

Gracias por la útil respuesta. ¿Alguna vez (el equipo Akkka) ha intentado agregar restricciones de tipo a los mensajes a los actores, o nunca se ha considerado una idea útil? – mkneissl

+2

Se ha hablado de eso en la lista en el pasado, pero siempre terminamos en el mismo lugar, TypedActor es para ese uso, y Actor es para un comportamiento dinámico total. Puedes experimentar con tu propia abstracción encima de ActorRef si quieres sentirte más en control. ¿Eso ayuda? Cheers, √ –

23

En Scala stdlib había an excuse para hacer que los actores básicos se tipearan (lo que no se aplica a Akka, porque no admite las recepciones anidadas, como recuerdo). Lift, a su vez, admite actores tipeados listos para usar.

Sin embargo, el uso de canales, todavía es posible crear actores inflexible con stdlib:

object TypedActor { 

    def apply[A](fun: PartialFunction[A, Any]): OutputChannel[A] = { 
    val sink = new SyncVar[Channel[A]] 
    actor { 
     val in = new Channel[A](self) 
     sink set in 
     loop { 
     in react { case any => reply(fun(any)) } 
     } 
    } 
    sink.get 
    } 

} 

sealed abstract class FooMessage 
case object Foo extends FooMessage 
case object Bar extends FooMessage 

object Test { 

    val fooActor = TypedActor[FooMessage]{ 
    case Foo => println("OK") 
    } 

    fooActor ! Foo 
    fooActor ! "Hello!" // doesn't compile -> Type mismatch; found: String("Hello!"); required: FooMessage; 

} 
2

En realidad, restringir un actor para tener solo un tipo de entrada no es muy útil. Lo que es más útil para mi mente es enumerar posibles entradas de una manera estrictamente tipada.

Hay un enfoque para las entradas estrictamente con tipo de actores (SynapseGrid):

case class Contact[T](...) 
case class Signal[T](contact:Contact[T], data:T) 

En su caso la interfaz consta de un solo contacto de entrada:

val FooInput = contact[FooMessage]("FooInput") 

Dentro SynapseGrid manejo marco de señales se define con el generador:

class FooActorBuilder extends SystemBuilder { 
    inputs(FooInput, OtherInput) 
    FooInput.foreach(fooMessage =>() //OK 
) 
    OtherInput.foreach(...) 
} 

Obviamente uno no se puede construir una señal con tipos incompatibles. Por lo tanto, tenemos tiempo de compilación de comprobación. En SynapseGrid hay una DSL para trabajar con señales y contactos.Por ejemplo, para enviar Foo o barra desde fuera:

val SomeOtherContact = contact[Boolean]("SomeOtherContact") 
SomeOtherContact.map(flag => if(flag) Foo else Bar) >> FooInput 

Por supuesto, uno puede simplemente enviar el mensaje:

val inputMessage = Signal(FooInput, Foo) 
actor ! inputMessage 
1

Suena como Akka de Akka's Typed Channel support fue haber tratado este, pero (según the commenthas already been removed from Akka in version 2.3).

En la documentación de Akka 2.2.3, hay una buena sección de "design background" que analiza las dificultades en el envío de mensajes escritos y respuestas de soporte.

También hay una buena charla NEScala por Roland Kuhn, Canales Akka proporcionado: Ejecución Tipo cálculos como macros ([YouTube]/[Slides]), que discute la implementación de canales mecanografiadas.

+1

Los canales con texto ya se han eliminado [de Akka en la versión 2.3] (http://doc.akka.io/docs/akka/snapshot/project/migration-guide-2.2.x-2.3.x.html) . "Los canales escritos fueron una característica experimental que decidimos eliminar: su implementación se basó en una función experimental de Scala para la cual no existe correspondencia en Java y otros lenguajes, y su uso no fue intuitivo". – dfan

Cuestiones relacionadas