Akka 演员避免变异状态
Akka actor avoiding mutating state
我对使用 Akka 演员还很陌生。最近,我读到了有关分布式参与者或远程参与者(无论您怎么称呼)的信息。到目前为止,我在我的 Actor 中使用状态并在我的接收方法中改变它已经很舒服了。快乐的时光!现在我想将我的 actor 分布在多个 JVM 上,我已经看到我的 actor 中的状态可能是个问题。
我确实读过关于 become 和 unbecome 的内容,我只是想知道 Akka 是如何在内部处理这个问题的?
状态:
class TestActor extends Actor {
var state = List.empty[String])
def receive =
case Add(elem) => state + elem
case Contains(elem) => sender() ! state.contains(elem)
}
}
删除状态后:
class TestActor extends Actor {
def receive = start(List.empty[String])
def start(lst: List[String]): Receive = {
case Add(elem) =>
context become start(lst+ elem)
case Contains(elem) =>
sender() ! lst.contains(elem)
}
}
第二个版本中的状态在 become 示例中去了哪里?
当使用 become
/unbecome
时,您只是在改变 actor 的行为而不是状态。状态保持不变。但是,在使用它时,您可能会泄漏内存(请查看此示例以获取更多详细信息:https://github.com/akka/akka/blob/master/akka-docs/rst/scala/code/docs/actor/UnnestedReceives.scala)
还有一件事值得一提,如果你的 actor 被 supervisor 重新启动,它将以其原始行为开始。
become/unbecome
通常用于初始化或状态的临时更改,例如流量控制。
从概念上讲,状态在执行堆栈上。 Receive
是 PartialFunction
的类型别名。 start
方法实现中的部分函数关闭了 lst
参数。然后可以使用来自执行上下文的参数值按需评估接收行为。
因此 lst
的大小确实在每次调用 start 方法时都会增加。
参考 内存泄漏,请注意默认情况下 become
是未嵌套的,因此没有内存泄漏。仅当您为 discardOld
参数传递 false
时,考虑到未来的 unbecome
,才会出现内存泄漏问题。
国家由阿卡机器控制。有一叠 receive
"blocks"
每次调用 become
或 unbecome
.
时都会发生变化
堆栈表示为an immutable List
bound to a var
。
有两个地方List
被替换了:
与 Erlang 相比,Akka 无法使用递归调用创建的执行堆栈来编码状态,因为这意味着阻塞调用。 Akka 无法承受对其任何线程的阻塞调用,因此它需要 var
.
Akka 的 receive
块 可能会给 递归调用的错觉,但请记住,一个 receive
块 returns 一个 PartialFunction
调用时调用 start
.
我对使用 Akka 演员还很陌生。最近,我读到了有关分布式参与者或远程参与者(无论您怎么称呼)的信息。到目前为止,我在我的 Actor 中使用状态并在我的接收方法中改变它已经很舒服了。快乐的时光!现在我想将我的 actor 分布在多个 JVM 上,我已经看到我的 actor 中的状态可能是个问题。
我确实读过关于 become 和 unbecome 的内容,我只是想知道 Akka 是如何在内部处理这个问题的?
状态:
class TestActor extends Actor {
var state = List.empty[String])
def receive =
case Add(elem) => state + elem
case Contains(elem) => sender() ! state.contains(elem)
}
}
删除状态后:
class TestActor extends Actor {
def receive = start(List.empty[String])
def start(lst: List[String]): Receive = {
case Add(elem) =>
context become start(lst+ elem)
case Contains(elem) =>
sender() ! lst.contains(elem)
}
}
第二个版本中的状态在 become 示例中去了哪里?
当使用 become
/unbecome
时,您只是在改变 actor 的行为而不是状态。状态保持不变。但是,在使用它时,您可能会泄漏内存(请查看此示例以获取更多详细信息:https://github.com/akka/akka/blob/master/akka-docs/rst/scala/code/docs/actor/UnnestedReceives.scala)
还有一件事值得一提,如果你的 actor 被 supervisor 重新启动,它将以其原始行为开始。
become/unbecome
通常用于初始化或状态的临时更改,例如流量控制。
从概念上讲,状态在执行堆栈上。 Receive
是 PartialFunction
的类型别名。 start
方法实现中的部分函数关闭了 lst
参数。然后可以使用来自执行上下文的参数值按需评估接收行为。
因此 lst
的大小确实在每次调用 start 方法时都会增加。
参考 内存泄漏,请注意默认情况下 become
是未嵌套的,因此没有内存泄漏。仅当您为 discardOld
参数传递 false
时,考虑到未来的 unbecome
,才会出现内存泄漏问题。
国家由阿卡机器控制。有一叠 receive
"blocks"
每次调用 become
或 unbecome
.
堆栈表示为an immutable List
bound to a var
。
有两个地方List
被替换了:
与 Erlang 相比,Akka 无法使用递归调用创建的执行堆栈来编码状态,因为这意味着阻塞调用。 Akka 无法承受对其任何线程的阻塞调用,因此它需要 var
.
Akka 的 receive
块 可能会给 递归调用的错觉,但请记住,一个 receive
块 returns 一个 PartialFunction
调用时调用 start
.