2015-10-13 133 views
4

重構其他程序員編寫的演員代碼時,我在演員A內遇到Future.onComplete回調的使用,這違背了使用akka.pattern.pipe的最佳做法。這是一個壞主意,因爲它暴露了競爭條件的可能性,因爲Future實例可能在不同的線程上執行。演員和未來:引用onComplete內的演員消息

看代碼,我們可以看到,有沒有sender也沒有那麼似乎很安全,至少這個特定場合任何可變var S爲onComplete塊中提到。然而,讓我想知道的一個灰色區域是對url的引用,尤其是text

是否有可能是類似於Closing Over An Akka Actor Sender In The Receive問題,競爭條件發生,使得當onComplete調用回調函數的時候,text值已經指的是不同的演員的消息,導致所有的地獄衝出重圍?

class B extends akka.actor.Actor { 
    def receive = { 
    case urlAndText: (String, String) => // do something 
    } 
} 

class A extends akka.actor.Actor { 
    case class Insert(url: String) 

    def fileUpload(content: String): String = ??? // returns the url of the uploaded content 
    val b = context.actorOf(Props(classOf[B])) 
    def receive = { 
    case text: String => 
     Future { 
     fileUpload(text) 
     } onComplete { 
     case Success(url) => 
      b ! Insert(url, text) // will this be 
     } 
    } 
} 

回答

4

text的引用應該沒問題。區別在於text的每個「實例」都是綁定到當前匹配塊範圍的新變量(從case text ...開始)。因此創建的Future關閉的值爲text就好了。

這是從sender(或sender()當DE-糖)的不同,其實際上是對Actor性狀所限定的方法,它返回由演員接收到的最近的消息的發送者上調用它的ActorRef,和所以稍後調用時可以給出不同的值(當最後調用FutureonComplete時)。

對於使用onComplete也是有懷疑的。更好的選擇是:

case text: String => 
    Future { 
    fileUpload(text) 
    } map { url => 
    Insert(url, text) 
    } pipeTo b 

現在的失敗也將發送到b,而不是悄悄地吞噬。

1

在這種情況下,你都不會遇到任何競爭條件雖然正如你指出這是不是一個特別好的主意來構建這樣的代碼一般。

提及urltext都很好。 url的值僅僅是一個成功完成的Future的提取,並且不管您是否在Actor中都不會改變。 text的值是不可變的字符串,並且在Future中關閉該值不應導致問題,因爲該字符串實例是不可變的。

正如你所記錄的關閉sender或var是一個問題,這是因爲作爲可變對象,這些值可能會在Future完成時發生變化,而不可變的值將保持不變,即使關閉它們也是如此。