Akka.NET 具有堆叠行为的 F# API 和执行组件



Akka 及其 Akka.NET 端口支持可切换行为 (http://getakka.net/docs/working-with-actors/Switchable%20Behaviors),不仅仅是让 actor 成为具有不同行为的 actor 的简单形式,还有一种行为堆栈的形式:参与者可以回到它之前的行为。这是通过方法"成为堆叠"和"成为不堆叠"来实现的。

在 F# 中,行为以不同的方式得到支持:不需要 Be 方法,而是执行组件函数可以定义多个邮箱处理处理程序,并调用不同的处理程序,从而有效地将执行组件切换到不同的行为。这适用于非堆叠行为,但如果参与者函数需要堆叠其行为怎么办?如何在 F# 中实现这一点?

更新。用用例来说明。考虑电话,其中参与者可以具有行为 DirectCall、ConferenceCall 和 OnHold。OnHold 行为可通过 DirectCall 和 Conference Call 访问,并且 OnHold 参与者可以接收消息以启动嵌套呼叫。嵌套呼叫完成后,参与者将返回到上一个呼叫,可以是 DirectCall 或 ConferenceCall。我看不出如何在不明确将完整堆栈发送给参与者的情况下实现这一点。毕竟,这还不错,我只是想知道 Akka.NET 是否提供了另一种方式。邮箱 Context.BecomeXXX 在 F# API 中仍然可用,但它在"actor"计算表达式中没有用处。

更新 2 我必须同意 Tomas Jansson 的观点,他在评论中推理说,他宁愿明确发送以前行为(或以前的状态)的堆栈,而不是依赖 Akka 内置的 BecomeStacked 方法隐藏历史并使其更难测试。因此,F# API 中缺少 BecomeXXX 方法并不会真正降低它的功能。

我写了一个简单的示例,说明如何使用MailboxProcessor解决它,概念是相同的,因此您应该能够轻松地将其转换为 akka.net:

type Message = 
    | Ping
    | Back
type State = {Behavior: State -> Message -> State; Previous: State -> Message -> State}
let rec pong state message =
    match message with 
    | Ping -> 
        printfn "Pong"
        {state with Behavior = superpong} 
    | Back ->
        {state with Behavior = state.Previous}
and superpong state message = 
    match message with 
    | Ping ->
        printfn "Super pong"
        {state with Behavior = pong} 
    | Back ->
        {state with Behavior = state.Previous}
        
let agent = new MailboxProcessor<Message>(fun inbox ->
    let setPrevious oldState newState = 
        {newState with Previous = oldState.Behavior}
    let rec loop state = 
        async {
            let! msg = inbox.Receive()
            return! loop (msg |> state.Behavior state |> setPrevious state)
        }
    loop {Behavior = pong; Previous = pong})
    
agent.Start()
agent.Post(Ping)
agent.Post(Ping)
agent.Post(Back)
agent.Post(Ping)
agent.Post(Ping)

输出为:

乒乓

超级乒乓球

超级乒乓球

乒乓

这个想法是,您将行为作为代理状态的一部分。请注意,必须使用 let rec ... and ... 语法定义函数,以便第二个函数可以在新状态下返回第一个函数。

更新简化了仅使用一种消息类型的示例。

相关内容

  • 没有找到相关文章

最新更新