38

Akka中,除了使用使用 RPC 样式编程模型的“Typed Actor”API 之外,是否有办法将发送给 Actor 的消息限制为特定的静态类型?

我可以在 Akka 中使用消息传递样式而不丢弃演员边界处的静态类型安全性吗?

例如,我想使用这样的代码:

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"

也许必须扩展一些基本特征或具有Either允许系统级消息(Exit等)的构造。

4

4 回答 4

27

然后,您必须将消息类型编码到 Actor ref 中,这将大大降低 ActorRegistry 之类的值。

此外,使用强大的机制,如“成为”(这是 Actor 模型的基础),输入消息的价值较低。

由于 Akka 在消息与当前行为不匹配时不会泄漏内存,因此将“错误”消息发送给“错误”actor 的风险不同。

此外,Actor 本质上是动态的,所以如果你想让它们成为静态,请使用 TypedActor(它不是 RPC,它就像 RPC 一样普通的 Actor,void 方法是 ! 调用,Future 返回类型是 !!! 和其他返回类型是基于!!)

常见的做法是在 Actor 的伴生对象中声明 Actor 可以接收哪些消息,这使得知道它可以接收什么变得非常容易。

这有帮助吗?

于 2011-04-05T11:24:51.913 回答
23

在 Scala 标准库中,有一个理由可以使基本的 actor 无类型(这不适用于 Akka,因为我记得它不支持嵌套接收)。反过来,Lift 支持开箱即用的类型化演员。

但是,使用通道,仍然可以使用 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;

}
于 2011-04-05T08:19:25.780 回答
2

实际上,将 Actor 限制为只有单一类型作为输入并不是很有用。对我来说更有用的是以严格类型的方式列出可能的输入。

有一种严格输入演员的方法(SynapseGrid):

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

在您的情况下,界面由一个输入触点组成:

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

在 SynapseGrid 框架内,信号处理由 Builder 定义:

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

显然,不能用不兼容的类型构造 Signal。因此我们有编译时检查。在 SynapseGrid 中有一个用于处理信号和联系人的 DSL。例如,从外部发送 Foo 或 Bar:

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

当然,可以简单地发送消息:

val inputMessage = Signal(FooInput, Foo)
actor ! inputMessage
于 2013-08-09T16:25:54.530 回答
1

听起来 Akka 的Akka 的 Typed Channel 支持已经解决了这个问题,但是(根据评论 已经从 Akka 版本 2.3 中删除)。

在 Akka 2.2.3 的文档中,有一个很好的“设计背景”部分讨论了支持类型化消息发送和响应的困难。

还有一个很好的 NEScala 演讲,由 Roland Kuhn 撰写,Akka Typed Channels:Implementing Type Calculations as Macros ( [YouTube] / [Slides] ),讨论了类型化通道的实现。

于 2014-06-20T17:44:12.940 回答