2011-04-05 5 views
37

Dans Akka, existe-t-il un moyen de limiter les messages aux acteurs à un type statique spécifique autre que l'utilisation des API "Typed Actor" qui utilisent un modèle de programmation de type RPC? Est-ce que je peux utiliser le style de passage de message avec Akka sans rejeter la sécurité de type statique aux limites de l'acteur?Comment limiter les messages d'acteur à des types spécifiques?

Par exemple, je voudrais utiliser le code comme ceci:

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" 

Peut-être faudrait étendre un trait de base ou une construction comme Either pour permettre des messages au niveau du système (Exit, etc.).

Répondre

25

Ensuite, vous auriez à encoder le type de message dans l'arbitre Acteur, qui drastiquement diminuer la valeur de quelque chose comme l'ActorRegistry. De plus, avec des mécaniques puissantes comme «devenir» (ce qui est fondamental pour le modèle d'acteur), taper les messages est moins intéressant. Comme Akka ne fuit pas la mémoire lorsqu'un message ne correspond pas au comportement actuel, il n'y a pas le même risque d'envoyer les «mauvais» messages au «mauvais» acteur.

En outre, les acteurs sont par nature dynamique, donc si vous voulez les rendre statiques, utilisez TypedActor (ce qui est RPC, il est tout aussi RPC que les acteurs réguliers, les méthodes vides sont! Appels, le type avenir de retour est !!! et d'autres types de retour sont basés sur !!)

La pratique courante consiste à déclarer quels messages un acteur peut recevoir dans l'objet compagnon de l'acteur, ce qui rend beaucoup plus facile de savoir ce qu'il peut recevoir.

Cela aide-t-il?

+2

Merci pour la réponse utile. Avez-vous (l'équipe akka) essayé d'ajouter des contraintes de type aux messages aux acteurs, ou cela n'a jamais été considéré comme une idée utile? – mkneissl

+2

On en a parlé dans la liste par le passé, mais on se retrouve toujours au même endroit, TypedActor est pour cette utilisation, et Actor est pour le comportement dynamique total. Vous pouvez expérimenter avec votre propre abstraction en plus d'ActorRef si vous voulez vous sentir plus en contrôle. Est ce que ça aide? Cheers, √ –

23

Dans Scala stdlib il y avait an excuse pour rendre les acteurs de base non typés (ce qui n'est pas applicable à Akka, car il ne supporte pas les reçus imbriqués, si je me souviens bien). Lift, à son tour, soutient les acteurs typés prêts à l'emploi.

Cependant, en utilisant des canaux, il est toujours possible de créer des acteurs fortement typés avec 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

Il n'est pas très utile de restreindre un acteur à un seul type en entrée. Ce qui est plus utile à mon avis, c'est de lister les entrées possibles d'une manière strictement typée.

Il y a une approche pour les entrées strictement typées des acteurs (SynapseGrid):

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

Dans votre cas, l'interface se compose d'un contact d'entrée unique:

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

Dans le traitement cadre SynapseGrid de signaux est défini avec Builder:

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

Impossible de construire un signal avec des types incompatibles. Ainsi, nous avons compiler le temps de vérification. Dans SynapseGrid, il y a un DSL pour travailler avec les signaux et les contacts.Par exemple, pour envoyer des Foo ou Bar de l'extérieur:

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

Bien sûr, on peut simplement envoyer le message:

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

On dirait Akka's Typed Channel support de Akka était d'avoir adressé, mais (selon the commenthas already been removed from Akka in version 2.3).

Dans la documentation d'Akka 2.2.3, il y a une bonne section "design background" qui traite des difficultés à supporter les envois et les réponses de messages typés.

Il y a aussi une bonne conversation de NEScala par Roland Kuhn, Akka typées canaux: mise en oeuvre Type calculs macros ([YouTube]/[Slides]), qui traite de la mise en œuvre des canaux typés.

+1

Les canaux dactylographiés ont déjà été supprimés [d'Akka dans la version 2.3] (http://doc.akka.io/docs/akka/snapshot/project/migration-guide-2.2.x-2.3.x.html) . "Les canaux typés étaient une fonctionnalité expérimentale que nous avons décidé de supprimer: son implémentation reposait sur une fonctionnalité expérimentale de Scala pour laquelle il n'y a pas de correspondance en Java et dans d'autres langues et son utilisation n'était pas intuitive." – dfan

Questions connexes