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 通常用于初始化或状态的临时更改,例如流量控制。

从概念上讲,状态在执行堆栈上。 ReceivePartialFunction 的类型别名。 start 方法实现中的部分函数关闭了 lst 参数。然后可以使用来自执行上下文的参数值按需评估接收行为。

因此 lst 的大小确实在每次调用 start 方法时都会增加。

参考 内存泄漏,请注意默认情况下 become 是未嵌套的,因此没有内存泄漏。仅当您为 discardOld 参数传递 false 时,考虑到未来的 unbecome,才会出现内存泄漏问题。

国家由阿卡机器控制。有一叠 receive "blocks" 每次调用 becomeunbecome.

时都会发生变化

堆栈表示为an immutable List bound to a var

有两个地方List被替换了:

与 Erlang 相比,Akka 无法使用递归调用创建的执行堆栈来编码状态,因为这意味着阻塞调用。 Akka 无法承受对其任何线程的阻塞调用,因此它需要 var.

Akka 的 receive 可能会给 递归调用的错觉,但请记住,一个 receive 块 returns 一个 PartialFunction 调用时调用 start.