是Akka演员执行互斥吗?

时间:2015-11-06 17:32:32

标签: akka

来自:https://www.chrisstucchio.com/blog/2013/actors_vs_futures.html 表明这是安全的:

class FooCounter extends Actor {
  var count: Long = 0

  def receive = {
    case Foo => { count += 1}
    case FooCountRequest => { sender ! count }
  }
}

是否可能会有多个同时接听的电话,使得计数值不确定。

我的理解是,唯一可以安全的方法是,如果对此对象的接收调用是自己的互斥。

2 个答案:

答案 0 :(得分:5)

多个线程永远不会同时调用receive方法。驻留在Actor邮箱中的消息由receive方法一次一个地处理。多个其他Actors或ActorSystem之外的函数可以同时将消息排入Actor的邮箱,但ActorSystem最终会对消息进行排序。来自docs

  

排队按发送操作的时间顺序进行,这意味着   从不同的演员发送的消息可能没有定义的顺序   在运行时由于分配演员的明显随机性   跨线程。

接收方法的串行处理是通过您从未实际从ActorSystem获取Actor值(具有接收)来保证的。相反,你只得到一个没有接收方法的ActorRef:

val actorSystem = akka.actor.ActorSystem()

//not an Actor but an ActorRef
val actorRef : ActorRef = actorSystem actorOf Props[FooCounter]

actorRef.receive(Foo) //COMPILE TIME ERROR!

"调用"的唯一方法receive方法是向ActorRef发送消息:

actorRef ! Foo //non-blocking, enqueues a Foo object in the mailbox

回到你的问题:ActorSystem充当所有Actor实例的伪互斥。

因此,示例中的代码绝对安全,并且只能在任何给定时间通过一条消息访问状态。

答案 1 :(得分:2)

完全赞同拉蒙。您可以认为它在您家外面有一个邮箱(Actor),邮件通过您的地址(ActorRef)进入您的邮箱,而您家中只有一个人可以照顾您的邮件一次一个

此外,更多的功能风格和维护代码的不变性。我会做以下事情:

class FooCounter extends Actor {

  def _receive(count: Long): Receive = {
    case Foo => 
      context.become(_receive(count + 1))

    case FooCountRequest => 
      sender() ! count
  }

  def receive = _receive(0L)

}

对于这个简单的例子,我和你的之间没有区别。但是当系统变得更复杂时,我的代码就不容易出错。