2013-03-22 95 views
6

背景阿卡發送關閉遠程演員

我想封閉發送到遠程的演員。遠程參與者應該對其數據運行關閉併發回結果。 可能這是不可取的,但爲了好奇這就是我想做的事情現在

但我觀察,如果一個封閉作爲一個匿名函數創建的,它抓住了外部對象也並試圖封送它,這如果外部對象不可序列化,則失敗,如在這種情況下。

class Client(server: ActorRef) extends Actor { 

    var every = 2 

    override def preStart() = { 
    println("client started. sending message....") 
    server ! new Message((x) => x % every == 0) 
    } 

} 

上面的代碼在調用遠程actor時會產生異常。我可以在方法preStart()

val every_ = every

定義本地變量和到位的演員成員變量的使用它。但我覺得這是一種解決方法,而不是解決方案。如果封閉更復雜,我將必須非常小心。

另一種方法是定義繼承自Function1[A,B]的類並將其實例作爲閉包發送。

class MyFunc(every : Int) extends Function1[Int,Boolean] with Serializable { 

    def apply(v1 :Int) : Boolean = { 
    v1 % every == 0 
    } 
} 


server ! new Message(new MyFunc(every)) 

但是,這將閉包定義與使用它的地方分開,並且破壞了使用函數式語言的全部目的。也使得定義閉包邏輯更加困難。

專用查詢

有沒有辦法可以推遲定義Function1.apply的身體,當我從一個本地定義封閉創建MyFunc的實例分配的apply的身體嗎?

例如

server ! new Message(new MyFunc(every){ // not valid scala code 
    x % every == 0 
}) 

where every是一個局部變量?

基本上我希望將兩種方法結合起來,即發送的Function1對象到遠程演員與Function1通過在其中創建Function1實例地方定義一個匿名函數所定義的身體。

感謝,

+0

我想你知道你在做什麼,但我想以確保你知道發送關閉被認爲是一個不好的做法,正如[文檔](http://doc.akka.io/docs/akka/snapshot/general/actor-systems.html)中明確解釋的那樣 - Actor最佳實踐alinea 3 – 2013-03-22 06:10:19

+0

感謝您指出。或者我可以將這種行爲封裝在actor中並動態創建它?即基於閉包來決定演員的行爲,而不是將閉包本身發送給演員。 – weima 2013-03-22 06:15:45

+0

有很多你可以做的,但我有一種感覺,你正試圖實現對特定問題的「錯誤」/尷尬的解決方案。我相信如果你編輯你的問題並描述你想達到的目標,你會在SO – 2013-03-22 06:26:01

回答

3

當然,你可以發送行爲的演員,但它被認爲是一種不好的做法,你的問題是對問題的一個很好的答案:「爲什麼」。

由於BGR指出在這個問題上有documentation特殊部分,但它沒有例子。

所以,當你發送閉包作爲消息時,你發送一些額外的「隱式」狀態。它可能不像文檔中提到的那樣易變,但即使在這種情況下,它也會產生問題。

這裏scala的問題在於它沒有嚴格的功能語言 - 它是多種語言的語言。換句話說,你可以在功能範式中使用命令式風格的代碼。沒有這樣的問題,例如haskell,這是純粹的功能。

如果您的「具體查詢」,我會建議您使用一組預定義的功能。這完全相當於帶有閉包的變體,但有一些簡潔的語法。由於您在運行時不生成代碼,因此您使用的所有函數都是在有限集內定義的,並且(看起來像)按值進行參數化。這使得你的代碼不像閉包一樣靈活,但最終它會成爲等價的情況。

所以,我的所有文章的中心思想:如果你要發送行爲的演員應該是穩如磐石的原子(在意義上沒有任何依賴關係)