如何定义F#actor函数以避免邮件装箱?

时间:2016-04-07 08:17:40

标签: f# akka.net

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#强度之一:类型推断。相反,我们必须将消息包装为将其转换为对象类型,然后将它们转换为我们期望的类型。

这种方法有两种选择:

  1. 始终列出相同类型的所有邮件案例。坏,坏,坏。
  2. 为每种消息类型定义一个actor类型。恕我直言,这可能会变得更加值得,因为决定创建一个新的演员类型不应该由语言特定的约束驱动。
  3. 我检查了Akka.NET bootcamp中的代码,他们正在使用第一种方法 - 使用消息装箱和转换。这是最好的可以做到的吗?

1 个答案:

答案 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