为什么我的演员创作了2次

时间:2017-07-14 03:55:02

标签: scala akka

我写了这段代码

class TestActor extends Actor {
   override def preStart(): Unit = {
      println("going to start my test actor")
   }

   override def postStop(): Unit = {
      println("came inside stop")
   }

   def receive = {
      case msg: TestMessage => sender ! s"Hello ${msg.name}"
   }
}

object TestActor {
   val props = Props(new TestActor)
   case class TestMessage(name: String)
}

我使用此客户端代码调用它

object MyApp extends App {
   val ac = ActorSystem("TestActorSystem")
   val a = new ClassA(ac).sayHello()
   val b = new ClassB(ac).sayHello()
   for {
      msg1 <- a
      msg2 <- b
   } {
      println(msg1)
      println(msg1)
   }
   Await.result(ac.terminate(), Duration.Inf)
}

class ClassA(ac: ActorSystem) {
   def sayHello(): Future[String] = {
      implicit val timeout = Timeout(5 seconds)
      val actor = ac.actorOf(TestActor.props)
      val msg = actor ? TestActor.TestMessage("foo")
      msg.map(_.asInstanceOf[String])
   }
}

class ClassB(ac: ActorSystem) {
   def sayHello() : Future[String]  = {
      implicit val timeout = Timeout(5 seconds)
      val actor = ac.actorOf(TestActor.props)
      val msg = actor ? TestActor.TestMessage("bar")
      msg.map(_.asInstanceOf[String])
   }
}

我看到输出

going to start my test actor
going to start my test actor
Hello foo
Hello foo
came inside stop
came inside stop

我的问题是,在伴侣对象中我创建了props对象作为val,因此只有1个val,而1个val有1个new TestActor实例

在客户端中,两个类都使用了相同的actor系统实例。因此,应该只有1个actor,来自classA和ClassB的两个消息都应该转到同一个actor。

但似乎两个类都有自己的Actor实例。

2 个答案:

答案 0 :(得分:3)

  

我的问题是,在伴侣对象中我创建了props对象作为val,因此只有1个val,而1个val有1个new TestActor实例

不是真的。是的,您定义了一个val,但valPropsProps类本质上是创建actor的秘诀。您定义的是用于创建TestActor的单个不可变配方。此配方可以多次使用,这是您在拨打ac.actorOf(TestActor.props)两次时所做的事情。这两个调用都使用相同的Props配方来创建新的TestActor;也就是说,您使用相同的配方来创建两个TestActor实例。

要重复使用单个TestActor,请执行@mfirry建议并在ClassAClassB之外创建此角色。这是一种方法:

object MyApp extends App {
  val ac = ActorSystem("TestActorSystem")

  val testActor = ac.actorOf(TestActor.props)

  val a = new ClassA(ac).sayHello(testActor)
  val b = new ClassB(ac).sayHello(testActor)
  for {
    msg1 <- a
    msg2 <- b
  } {
    println(msg1)
    println(msg1)
  }
  Await.result(ac.terminate(), Duration.Inf)
}

class ClassA(ac: ActorSystem) {
  def sayHello(actor: ActorRef): Future[String] = {
    implicit val timeout = Timeout(5 seconds)
    val msg = actor ? TestActor.TestMessage("foo")
    msg.map(_.asInstanceOf[String])
  }
}

class ClassB(ac: ActorSystem) {
  def sayHello(actor: ActorRef): Future[String]  = {
    implicit val timeout = Timeout(5 seconds)
    val msg = actor ? TestActor.TestMessage("bar")
    msg.map(_.asInstanceOf[String])
  }
}

答案 1 :(得分:1)

这是由actorOf创建一个新演员引起的,所以两次actorOf它会创建2 TestActor。您可以使用actorSelection来避免第二次创建,例如:

class ClassA(ac: ActorSystem) {
  def sayHello(): Future[String] = {
    implicit val timeout = Timeout(5 seconds)
    val actor = ac.actorOf(Props[TestActor], "test")
    println(actor.path)
    val msg = actor ? TestMessage("foo")
    msg.map(_.asInstanceOf[String])
  }
}

class ClassB(ac: ActorSystem) {
  def sayHello() : Future[String]  = {
    implicit val timeout = Timeout(5 seconds)
    val actor = ac.actorSelection("akka://TestActorSystem/user/test")
    val msg = actor ? TestMessage("bar")
    msg.map(_.asInstanceOf[String])
  }
}