Jak ograniczyć wiadomości aktora do określonych typów?

W Akka , czy istnieje sposób, aby ograniczyć Wiadomości do aktorów, aby były określonego typu statycznego, innego niż używanie API "Typed Actor", które używają modelu programowania w stylu RPC?

Czy Mogę używać stylu przekazywania wiadomości z Akką bez wyrzucania statycznego bezpieczeństwa na granicy aktora?

Na przykład, chciałbym użyć kodu w ten sposób:

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"

Być może trzeba by rozszerzyć jakąś podstawową cechę lub mieć konstrukcję podobną do Either, aby umożliwić komunikaty na poziomie systemu (Exit, itd.).

Author: Jacek Laskowski, 2011-04-05

4 answers

Wtedy musiałbyś zakodować typ wiadomości do Ref aktora, co drastycznie zmniejszyłoby wartość czegoś takiego jak Registry ACTOR.

Również z potężnymi mechanikami, takimi jak "become" (co jest fundamentalne dla modelu aktora), pisanie wiadomości jest mniej wartościowe.

Ponieważ Akka nie wycieka pamięci, gdy wiadomość nie jest dopasowana do bieżącego zachowania, nie ma takiego samego ryzyka wysłania "złych" wiadomości do "niewłaściwego" aktora.

Ponadto aktorzy są przez nature dynamic, więc jeśli chcesz, aby były statyczne, użyj TypedActor (który nie jest RPC, jest tak samo RPC jak zwykli aktorzy, metody void są ! połączenia, przyszły Typ powrotu jest !!! i inne typy zwrotów są oparte na !!)

Powszechną praktyką jest deklarowanie, jakie wiadomości aktor może otrzymać w obiekcie towarzyszącym aktora, co znacznie ułatwia poznanie, co może otrzymać.

Czy to pomaga?

 26
Author: Viktor Klang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-09 18:44:00

W Scali stdlib był pretekst do robienia podstawowych aktorów nieopisanych (co nie dotyczy Akki, bo nie obsługuje zagnieżdżonych odbiorników, o ile pamiętam). Winda z kolei wspiera typowanych aktorów.

Jednak, używając kanałów, nadal możliwe jest tworzenie silnie wpisanych aktorów za pomocą 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;

}
 23
Author: Vasil Remeniuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-05 08:31:33

W rzeczywistości ograniczenie aktora do posiadania tylko jednego typu jako wejścia nie jest zbyt użyteczne. Bardziej przydatne dla mnie jest wymienienie możliwych wejść w ściśle wpisany sposób.

Istnieje podejście do ściśle wpisanych wejść aktorów (SynapseGrid):

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

W Twoim przypadku interfejs składa się z pojedynczego kontaktu wejściowego:

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

W ramach SynapseGrid obsługa sygnałów jest zdefiniowana za pomocą Builder:

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

Oczywiście nie można skonstruować Sygnał z niekompatybilnymi typami. W ten sposób mamy sprawdzanie czasu kompilacji. W SynapseGrid znajduje się DSL do pracy z sygnałami i kontaktami. Na przykład, aby wysłać Foo lub Bar z zewnątrz:

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

Oczywiście można po prostu wysłać wiadomość:

val inputMessage = Signal(FooInput, Foo)
actor ! inputMessage
 2
Author: Arseniy Zhizhelev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-09 16:25:54

Wygląda na to, że obsługa kanału Akka miała się tym zająć, ale (zgodnie z komentarz został już usunięty z Akka w wersji 2.3).

W dokumentacji Akka 2.2.3 znajduje się dobra sekcja "tło projektu", która omawia trudności w obsłudze wysyłanych wiadomości i odpowiedzi.

Jest też dobra rozmowa Nescala Rolanda Kuhna, Akka Typed Channels: Implementing Type Calculations as Makra ([YouTube] / [Slides] ), który omawia implementację typowanych kanałów.

 1
Author: Josh Rosen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:19:19