3

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

// 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方法。但是,创建的部分函数似乎以某种方式保留了早期调用的状态。我发现这个问题有点难以解释,但我已尽力在代码中的注释中这样做,所以请阅读这些,我会回答任何不清楚的地方。

4

1 回答 1

3

你的逻辑有点复杂,但我会试一试可能是什么问题:

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

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

但我会建议重写该代码,因为看起来发生变化的状态是某种类型的信息,并且您正在使用 Akka 的演员状态转换来操纵这个状态,这根本不是最好的工具。become并且unbecome旨在用于从演员行为的不同状态过渡。也就是说,一个actor可以在任何时候有不同的行为并且你使用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
        }
    }

}

我可能没有捕捉到你的整个想法,但你明白了。

于 2012-11-15T16:46:45.727 回答