2015-11-06 82 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) 

} 

對於這個簡單的例子,我和你的沒有區別。但是當系統變得更復雜時,我的代碼不太容易出錯。