2012-02-16 122 views
3

最近我從斯卡拉演員切換到阿卡演員,但注意到,阿卡演員使用的ActorRef而不是實例對象:談到斯卡拉演員阿卡演員:一個實例調用方法在

val actorRef: ActorRef = Actor.actorOf(new MyActor) 

所以,我想:

val myActor = new MyActor 
val actorRef: ActorRef = Actor.actorOf(x) 

...有兩個:1)ActorRef發送消息和2)MyActor來調用方法。
但我得到:

akka.actor.ActorInitializationException: ActorRef for instance of actor [MyActor] is not in scope. 

所以我的問題是:我怎樣才能獲得一個實例上,我可以叫ActorRef式的方法,如從MyActor實例!也是方法(某些類型的)?

+0

你爲什麼要對演員調用方法?什麼樣的方法?我認爲直接對演員調用方法是危險的,你應該考慮改變它的工作方式。 – Submonoid 2012-02-16 13:11:16

+0

@Submonoid我知道這很危險。這是一種方便的方法,你可以在我的例子中看到它不會改變演員的內部狀態(危險部分),但只會發送一條消息。 – 2012-02-16 13:14:58

回答

14

你正在做什麼是可怕想法。所以現在就停下來,離開鍵盤,然後去the Akka Documentation,然後讀一讀Actor。

考慮一下:

class YourActor extends Actor { 
    var mutableStuff = ... 
    def receive = { 
    case _ => 
     // mess with mutableStuff 
    } 
    def publicMethod = // mess with mutableStuff 
} 

現在,設置您的系統,並開始發送消息,並呼籲其他線程的方法。繁榮!

你在做準確地什麼Akka和演員模型幫助您防止。你實際上向後彎曲,以打破他們已經修好的東西:)他們不會讓你這樣做。

現在,您可以通過直接訪問方法來進行單元測試,但您需要一個TestActorRef。在閱讀文檔時,請閱讀「測試」一節。

+0

感謝您弄清楚。我想這就是'ActorRef'甚至存在的原因(除了其他事實,例如它的可串行化以跨網絡發送)。我不想改變演員的可變部分,這是危險的(當它從另一個線程中調用時),我知道。如上所述,這只是便利的方法。但你的對,我應該採取另一種方法,而不是打破演員模型。 – 2012-02-16 13:24:13

+0

我明白了,但事實並非如此。 Akka不僅僅是一個工具包,它是併發,容錯編程的典範。你正在建造的東西真的只是一幢房子。這將是「方便」,直到某個地方的小丑,不知道任何更好的,變異的狀態。你所做的只是把一個沒有鎖的門放在地獄上,上面有一個標誌,上面寫着「請不要打開」。 – 2012-02-16 13:27:16

+0

好的比喻。我擔心我就是那個小丑,分別是我未來的自我:D – 2012-02-16 13:33:18

1

我最喜歡的是以下,很髒:
有沒有更好的方法?

import akka.actor._ 

trait ActorCom { 
    var actorRefForInitialization: ActorRef = _ 
    lazy val actorRef: ActorRef = actorRefForInitialization 
    def ?(message: Any)(implicit channel: UntypedChannel = NullChannel, timeout: Actor.Timeout = Actor.defaultTimeout) = actorRef ? message 
    def !(msg: Any)(implicit sender: UntypedChannel) = actorRef ! msg 
    def start = actorRef.start 
} 

object AkkaActorFactory { 
    def apply[A <: Actor](newInstance: => A with ActorCom): A with ActorCom = { 
    var instance: Option[A with ActorCom] = None 
    val actorRef = Actor.actorOf({ 
     instance = Some(newInstance) 
     instance.get 
    }) 
    instance.get.actorRefForInitialization = actorRef 
    instance.get.actorRef // touch lazy val in ActorCom, to make it equal to actorRef and then its fixed (immutable) 
    instance.get 
    } 
} 

class MyActor extends Actor { 
    def receive = { 
    case "test1" => println("good") 
    case "test2" => println("fine") 
    case _  => println("bad") 
    } 
    def sendTestMsg2Myself = self ! "test2" 
} 

val myActor = AkkaActorFactory(newInstance = new MyActor with ActorCom) 
myActor.start 
myActor ! "test1" 
myActor.sendTestMsg2Myself // example for calling methods on MyActor-instance 
myActor ! PoisonPill