2015-11-06 62 views

回答

4

接收方法永远不会被多个线程同时调用。驻留在Actor的邮箱中的消息由receive方法一次处理一次。多个其他Actor或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! 

只有这样,才能“援引”接收的方法是将消息发送到ActorRef:

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

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

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

+0

谢谢。非常有用。所以这听起来像是演员的主要好处,而不是实际上启用并发,而是确保并发系统中的操作序列化。 – user48956

+0

每个Actor可以一次处理一条消息,因此使用多个Actor可以进行并发处理。 –

+0

嗯....在https://github.com/spray/spray/blob/master/examples/spray-can/simple-http-server/src/main/scala/spray/examples/DemoService.scala 。这个http服务器一次只能处理一个请求? – user48956

1

完全同意拉蒙。你可以想象它有一个房子外面的邮箱(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) 

} 

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