来自: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 }
}
}
是否可能会有多个同时接听的电话,使得计数值不确定。
我的理解是,唯一可以安全的方法是,如果对此对象的接收调用是自己的互斥。
答案 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)
}
对于这个简单的例子,我和你的之间没有区别。但是当系统变得更复杂时,我的代码就不容易出错。