我在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
方法。但是,创建的部分函数似乎以某种方式保留了早期调用的状态。我发现这个问题有点难以解释,但我在代码中的评论中尽我所能,所以请阅读这些内容,我会回答任何不清楚的问题。
答案 0 :(得分:2)
你的逻辑有点令人费解,但我会考虑可能出现的问题:
如果someCondition
为真,那么你的演员进入一个状态,我们称之为S1,其特征是值为Information(List())。然后你返回(顺便说一句,避免使用return
,除非绝对必要)一个接收方法,它将你的actor放入一个以列表信息(somePreviousList:+ x)为特征的状态S2。所以在这一点上你的状态堆栈顶部有S1。但是当您收到Bar(x)
消息时,状态S2将被推送,从而覆盖S1并且您实际上转换为以旧值+新x
的信息为特征的状态。
或类似的东西,你的演员的递归有点令人着迷。
但是我会建议重写代码,因为看起来改变的状态是类型信息的东西,你正在使用Akka的actor状态转换来操纵这个状态,这根本不是最好的工具。 become
和unbecome
旨在用于从演员的行为的不同状态转换。也就是说,演员可以随时使用不同的行为,并使用become
和unbecome
来改变这些行为。
为什么不做这样的事情?
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
}
}
}
我可能没有抓住你的整个想法,但是你得到了照片。