0

我阅读了 Akka 文档,但我不明白:

class MyActor extends Actor {
  private var _state = 0

  override def receive: Receive = {
    case x: Int =>
      if (x != _state) {
        println(s"---------> fail: ${x} and ${_state}")
      }
      _state = x + 1
  }
}


implicit val system = ActorSystem("my-system")
  val ref = system.actorOf(Props[MyActor], "my-actor")
  (0 to 10000).foreach { x =>
    ref ! x
  }

如果我使用-method进行更改,我有一个_state不是@volatile和不是atomic但同时_state始终正确的变量。!Akka 如何保护和更新 Actor 的内部状态?

4

2 回答 2

3

Akka 是计算的 Actor 模型的实现。演员模型做出的(可以说)关键保证之一是演员一次只处理一条消息。仅仅由于对参与者_state是私有的,您就可以获得至少与拥有对象的所有方法一样强大的并发保证,并且发送消息@synchronized!操作是非阻塞的。

在引擎盖下,它如何工作以及如何执行保证的粗略(在一些地方进行了简化,但粗略的笔划是准确的)概述是:

  • 使用构造一个实例,将Props对该实例的唯一 JVM 引用放在一个(我被告知这个术语,以及 Akka 的深层内部是“地牢”,受到 Akka 早期开发团队的启发位于瑞典乌普萨拉以前的监狱中的办公室),并使用. 同时(从技术上讲,这发生在已经返回 的之后),它构造一个允许用户代码引用参与者的。ActorSystemMyActorActorCellActorCellmy-actorsystem.actorOfActorRefActorRef

  • 在 内部ActorCellreceive方法被调用并且结果PartialFunction[Any, Unit](具有 的类型同义词Receive)被保存在ActorCell对应于参与者行为的字段中。

  • (至少对于 local )上的!操作会解析哪个调度程序负责 Actor 并将消息传递给调度程序。然后调度程序将消息排入对应的邮箱中(这是以线程安全的方式完成的)。ActorRefActorRefActorCellmy-actor

  • 如果当前没有调度任务来处理来自参与者邮箱的消息,则将此类任务排入调度程序的执行上下文以从ActorCell' 的邮箱中取出一些(可配置的)消息并处理它们,一次一个, 在一个循环中。在那个循环之后,如果有更多消息要处理,另一个这样的任务将被排队。处理消息包括将其传递给Receive存储在ActorCell's 的行为字段中(这种机制允许context.become改变行为的模式)。

它是提供保证只有一个线程调用Receive逻辑的核心的最后一点。

于 2021-05-30T22:17:29.550 回答
-1

这是 Akka Actors 的经典模型。如果您只是学习演员,那么您应该使用类型化演员,因为这是未来支持的模型。

对于类型化的 Actor,Actor 系统保存每个 Actor 的状态,而不是 Actor 本身。当演员需要处理消息时,演员系统会将当前状态传递给演员。Actor 将在处理完消息后将新状态返回给 Actor 系统。

类型化模型避免了所有同步问题,因为它不使用任何外部状态,它只使用传递给它的状态。而且它不修改任何外部状态,它只是返回一个修改后的状态值。

如果您必须使用 Classic Actor,那么您可以使用context.become而不是使用var.

于 2021-05-31T05:51:23.843 回答