通过将参数传递给“变为”来改变Akka actor状态

时间:2012-11-15 15:07:50

标签: scala akka actor

我在Akka演员中使用become时遇到了一些麻烦。基本上,我的演员有这样的结构:

// This is where I store information received by the actor
// In my real application it has more fields, though.
case class Information(list:List[AnyRef]) {
    def received(x:AnyRef) = {
        Information(list :+ x)
    }
}

class MyActor extends Actor {

    // Initial receive block that simply waits for a "start" signal
    def receive = {
        case Start => {
            become(waiting(Information(List())))
        }
    } 

    // The main waiting state. In my real application, I have multiple of
    // these which all have a parameter of type "Information"
    def waiting(info:Information):Receive = {

        // If a certain amount of messages was received, I decide what action
        // to take next.
        if(someCondition) {
            decideNextState(x)
        }

        return {
            case Bar(x) => {
                //
                // !!! Problem occurs here !!!
                //
                // This is where the problem occurs, apparently. After a decision has been
                // made, (i.e. decideNextState was invoked), the info list should've been
                // cleared. But when I check the size of the info list here, after a decision
                // has been made, it appears to still contain all the messages received
                // earlier.
                //
                become(waiting(info received x))
            }
        }
    }

    def decideNextState(info:Information) {
        // Some logic, then the received information list is cleared and 
        // we enter a new state.
        become(waiting((Information(List())))
    }
}

很抱歉这段长代码片段,但我真的无法让它变小。

问题发生的部分在注释中标出。我将一个参数传递给返回Receive部分函数的方法,然后传递给become方法。但是,创建的部分函数似乎以某种方式保留了早期调用的状态。我发现这个问题有点难以解释,但我在代码中的评论中尽我所能,所以请阅读这些内容,我会回答任何不清楚的问题。

1 个答案:

答案 0 :(得分:2)

你的逻辑有点令人费解,但我会考虑可能出现的问题:

如果someCondition为真,那么你的演员进入一个状态,我们称之为S1,其特征是值为Information(List())。然后你返回(顺便说一句,避免使用return,除非绝对必要)一个接收方法,它将你的actor放入一个以列表信息(somePreviousList:+ x)为特征的状态S2。所以在这一点上你的状态堆栈顶部有S1。但是当您收到Bar(x)消息时,状态S2将被推送,从而覆盖S1并且您实际上转换为以旧值+新x的信息为特征的状态。

或类似的东西,你的演员的递归有点令人着迷。

但是我会建议重写代码,因为看起来改变的状态是类型信息的东西,你正在使用Akka的actor状态转换来操纵这个状态,这根本不是最好的工具。 becomeunbecome旨在用于从演员的行为的不同状态转换。也就是说,演员可以随时使用不同的行为,并使用becomeunbecome来改变这些行为。

为什么不做这样的事情?

class MyActor extends Actor {

    private var info = Information(List.empty)

    def receive = {
        case Start => info = Information(List()) //a bit redundant, but it's just to match 1:1 with your code
        case Bar(x) => {
            if (someCondition) {
                info = Information(List.empty)
            }
            info = info received x
        }
    }

}

我可能没有抓住你的整个想法,但是你得到了照片。