Akka.NET提供了一个F#API,通过Akka邮箱将Akka actor定义为F#函数变得微不足道。并且只要使用单个区分联合来描述由actor处理的所有消息,则actor邮箱是强类型的。问题在于将所有消息定义放在单一类型(区别联合)中通常会使这种类型变得混乱:一个参与者经常响应不同类别的消息,例如:远程客户端发送的消息和内部通信中使用的消息。例如,actor可以生成内部作业并通过内部组件获得通知。使用不同的(内部)类型定义这些内部消息是有意义的,但是actor的邮箱chages不再是强类型,并且actor的函数看起来像这样:
let rec loop () =
actor {
let! message = mailbox.Receive ()
match box message with
| :? PublicMessage as msg -> handlePublicMessage msg
| :? PrivateMessage as msg -> handlePrivateMessage msg
| _ -> raise (InvalidOperationException(sprintf "Invalid message type %A" message))
return! loop ()
}
loop ()
我不喜欢的是,这种方法消除了核心F#强度之一:类型推断。相反,我们必须将消息包装为将其转换为对象类型,然后将它们转换为我们期望的类型。
这种方法有两种选择:
我检查了Akka.NET bootcamp中的代码,他们正在使用第一种方法 - 使用消息装箱和转换。这是最好的可以做到的吗?
答案 0 :(得分:0)
好吧,在我看来有两个问题 - 内部消息和拳击/类型安全。
据我了解演员模型,没有私信。演员可以回复消息,也可以不响应消息。如果你真的想要一个异步私有逻辑,我建议在处理公共消息时使用异步函数,而不是必须公开的不同演员消息。
对于类型安全,虽然我还没有尝试过,但似乎还有另一种方法可以避免计算表达式来生成actor并使用提供的泛型actorOf
函数来代替:
let handleMessage message =
match message with
| PublicMessage as msg -> handlePublicMessage msg
| PrivateMessage as msg -> handlePrivateMessage msg
| _ -> raise (InvalidOperationException(sprintf "Invalid message type %A" message))
let actorRef = spawn system "my-actor" <| actorOf handleMessage
它基本上是一种类型安全的替代选项1.我个人在一种联合类型中列出所有支持的消息类型时没有看到问题。要么actor知道它的消息(最好是默认的回退),要么你想要完全面向对象,没有类型,只有盒装的动态消息。
更多信息,例如文档中的示例:http://getakka.net/docs/FSharp%20API#creating-actors-with-actor-computation-expression