38 votes

Pourquoi les messages destinés aux acteurs Akka ne sont pas typés ?

Sur Akka Pour les acteurs, existe-t-il un moyen de restreindre les messages à un type statique spécifique, autrement qu'en utilisant les API "Acteurs typés" qui utilisent un modèle de programmation de type RPC ?

Puis-je utiliser le style de passage des messages avec Akka sans renoncer à la sécurité statique des types aux frontières des acteurs ?

Par exemple, j'aimerais utiliser un code comme celui-ci :

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"

Il faudrait peut-être étendre un trait de base ou avoir une construction du type Either pour permettre les messages de niveau système ( Exit etc.).

27voto

Viktor Klang Points 14826

Il faudrait alors coder le type de message dans la référence de l'acteur, ce qui diminuerait considérablement la valeur de quelque chose comme le registre des acteurs.

De plus, avec des mécanismes puissants comme le "devenir" (qui est fondamental pour le modèle d'acteur), taper les messages a moins de valeur.

Comme Akka ne fait pas fuir 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.

De plus, les acteurs sont par nature dynamiques, donc si vous voulez les rendre statiques, utilisez TypedActor (qui n'est pas RPC, il est tout aussi RPC que les acteurs normaux, les méthodes void sont des appels !, le type de retour Future est ! !! et les autres types de retour sont basés sur ! !)

La pratique courante consiste à déclarer les messages qu'un Acteur peut recevoir dans l'objet compagnon de l'Acteur, ce qui permet de savoir très facilement ce qu'il peut recevoir.

Est-ce que ça aide ?

23voto

Vasil Remeniuk Points 12487

Dans Scala stdlib, il y avait une excuse pour rendre les acteurs de base non typés (ce qui n'est pas applicable à Akka, car il ne supporte pas les récepteurs imbriqués, si je me souviens bien). Lift, à son tour, prend en charge les acteurs typés dès le départ.

Cependant, en utilisant les 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;

}

2voto

Arseniy Zhizhelev Points 910

En fait, restreindre un Acteur à n'avoir qu'un seul type en entrée n'est pas très utile. Ce qui est plus utile à mon sens est de lister les entrées possibles d'une manière strictement typée.

Il existe 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 consiste en un seul contact d'entrée :

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

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

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

Il est évident que l'on ne peut pas construire un signal avec des types incompatibles. Nous avons donc une vérification au moment de la compilation. Dans SynapseGrid, il existe un DSL pour travailler avec les signaux et les contacts. Par exemple, pour envoyer Foo ou Bar depuis 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

1voto

Josh Rosen Points 2540

Il semble que la méthode Akka Support des canaux typés d'Akka abordera cette question. Dans la documentation, il y a un bon "expérience en matière de design" qui traite des difficultés de prise en charge des envois et des réponses aux messages typés.

Il y a aussi un bon exposé de Roland Kuhn sur NEScala, Canaux typés Akka : Implémentation des calculs de type en tant que macros ( [YouTube] / [Diapositives] ), qui traite de l'implémentation des canaux typés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X