2014-04-01 110 views
10

我剛剛開始學習斯卡拉的Akka演員。我的理解是,演員收到的消息在演員的郵箱中排隊,並且一次處理一個。通過一次處理一個消息,可以緩解併發問題(競爭條件,死鎖)。在Akka演員中使用期貨

但是,如果演員創建未來做與消息相關的工作,會發生什麼?由於未來是異步的,Actor可以開始處理接下來的幾條消息,而與之前的消息相關的未來仍在運行。這不會造成競爭狀況嗎?在Actor的receive()方法中如何安全地使用期貨來執行長時間運行的任務?

+0

你是指與未來相關的行動對演員內部的變量進行操作?那麼是的,這是一個競爭條件。 –

回答

1

如果您需要改變未來狀態而不阻止傳入消息,則可能需要重新考慮重新設計您的演員模型。我會爲每個將要使用這些期貨的任務介紹單獨的角色。畢竟,演員的主要任務是保持其狀態而不讓其逃脫,從而提供安全的併發性。爲那些長期執行的任務定義一個參與者,他們的責任僅僅是照顧到這一點。

您可能需要考慮使用akka's FSM,而不是手動處理狀態,以便更清楚地瞭解什麼時候更改。當我處理更復雜的系統時,我首先喜歡這種方法來處理難看的變量。

16

在演員中使用期貨的最安全的方式是在未來只使用pipeTo並將其結果作爲消息發送給演員(可能是同一演員)。

import akka.pattern.pipe 

object MyActor { 

    def doItAsynchronously(implicit ec: ExecutionContext): Future[DoItResult] = { 
    /* ... */ 
    } 

} 

class MyActor extends Actor { 

    import MyActor._  
    import context.dispatcher 

    def receive = { 
    case DoIt => 
     doItAsynchronously.pipeTo(self) 
    case DoItResult => 
     // Got a result from doing it 
    } 

} 

這確保您不會改變actor中的任何狀態。

+2

+1,並且萬一從這個答案中不清楚,'doItAsynchronously'應該*不*改變任何演員的狀態。事實上,如果您可以將該功能移至伴侶對象(或其他任何無法訪問您演員的「this」)的對象,那麼對此保持誠實會更容易。 –

+0

好的一點,我會編輯我的例子來說清楚。 – Ryan