【问题标题】:Turning Scala Actors To Akka Actors: One Instance To Call Methods On将 Scala Actors 转换为 Akka Actors:一个调用方法的实例
【发布时间】:2012-02-16 13:04:52
【问题描述】:

最近我从 scala actor 切换到 akka actor,但注意到 akka actor 使用 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 实例的方法?

【问题讨论】:

  • 你为什么要调用actor的方法?什么样的方法?我认为直接在actor上调用方法是危险的,你应该考虑改变它的工作方式。
  • @Submonoid 我知道那很危险。这是一种方便的方法,正如您在我的示例中看到的那样,它不会改变参与者的内部状态(危险部分),而只会发送一条消息。

标签: scala actor akka


【解决方案1】:

你正在做的是一个糟糕的想法。所以现在就停下来,离开键盘,去the Akka Documentation阅读Actors。

考虑一下:

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

现在,设置您的系统并开始发送消息并从其他线程调用该方法。轰隆隆!

您正在准确地做 Akka 和 Actor 模型帮助您防止的事情。您实际上是在向后弯腰以破坏他们已经修复的东西:) 他们不会让您这样做。

现在,您可以通过直接访问方法进行单元测试,但您需要一个 TestActorRef。在阅读文档时,请通读测试部分。

【讨论】:

  • 谢谢你把事情说清楚。我想这就是“ActorRef”甚至存在的原因(除了其他事实,例如它可以序列化以通过网络发送)。我不想改变演员的可变部分,这很危险(当它从另一个线程调用时),我知道。如前所述,这只是方便的方法。但你说得对,我应该采取另一种方法而不是破坏 Actor 模型。
  • 我明白了,但不是这样。 Akka 不仅仅是一个工具包,它还是一个并发、容错编程的范式。你正在建造的实际上只是一个纸牌屋。这将是“方便的”,直到某个地方的某个小丑,不知道任何更好的变异状态。你所做的只是在地狱上放了一扇未上锁的门,上面写着“请不要打开”。
  • 很好的类比。我担心我是那个小丑,分别是我未来的自己:D
  • 也许阿卡人会想办法阻止我破解这个。
  • 不仅如此。但是在 Akka 中容错的方式是,Actor instance 将在失败时被替换,所以你会挂在一个损坏的引用上。只是不要这样做。
【解决方案2】:

我能想到的最好的是以下,很脏:
有没有更好的办法?

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

【讨论】:

    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 2016-05-25
    相关资源
    最近更新 更多