怎么给演员起名字?

How to name an actor?

我的 Web 应用程序中的数据层由 Akka actor 组成。每当我需要访问数据时,我都会像这样调用 ActorSystem 机制:

val myActor = system.actorOf(Props[MyActor], name = "myactor")      
implicit val timeout = Timeout(120 seconds)
val future = myActor ? Request1
val result = Await.result(future, timeout.duration)

我用的是Play,ActorSystem变量是通过注入获取的:

class MyClass @Inject() (system: ActorSystem)

但是我收到以下异常,说演员名称在我访问函数的 时不是唯一的,如何解决这个问题?如何命名actor,考虑到可以被多个线程并发使用?

play.api.http.HttpErrorHandlerExceptions$$anon: Execution exception[[InvalidActorNameException: actor name [myactor] is not unique!]]

** 编辑 **

我要实现的目标类似于在 EJB 模型中拥有一个实体 Bean 容器,其中每个参与者都是一个实体 Bean。我注意到的不同之处在于,演员不会根据需要自动 created/destroyed。

根据您的目标,问题可能不是如何命名演员,而是何时创建演员。每次需要访问某些数据时,您都在创建一个新的参与者。我想你不会在不再需要老演员时阻止他们。

您可能应该创建一个演员一次(如果您想要一个演员池,但使用不同的名称,则可以创建多次)并在以后通过在某处保留 ActorRef 或使用 dependency injected actors. You can also use system.actorFor or system.actorSelection 来重用它(取决于你使用的 Akka 版本)如果你真的需要的话。

大多数时候你甚至不需要明确的 ActorRef 因为你想要 reply to a sender 一些消息。

如果每次都必须创建一个单独的演员,请参阅 Wonpyo 的回答。不过,在我看来,您可以直接使用 Future

有一个很棒的guide on Actors in the Akka documentation

编辑:

既然你指定了你希望每个演员都像 DAO class,我认为它应该看起来像:

// Somewhere in some singleton object (injected as dependency)
val personDao : ActorRef = system.actorOf(Props[PersonDaoActor], name = "personDao")
val fruitDao  : ActorRef = system.actorOf(Props[FruitDaoActor],  name = "fruitDao")

然后,当您需要访问一些数据时:

val johnSmithFuture = personDao ? Get("John Smith")
johnSmithFuture.map {
  case Person(name, age) => println(s"${name} ${age}")
}

或者,您可以使用 system.actorFor("personDao")(或 Akka 2.4 中等效的 system.actorSelection)代替 personDao。您也可以 inject actors directly.

如果您希望多个参与者并行处理您的消息,您可以使用 routers。示例:

val personDao: ActorRef =
  system.actorOf(RoundRobinPool(5).props(Props[PersonDaoActor]), "personDao")

它将创建您的 PersonDaoActor 的 5 个实例,并在这 5 个参与者之间分发发送到 personDao 的任何消息,因此您可以并行处理 5 个查询。如果 5 个演员都忙,消息将排队。

在这种情况下使用 Await 违背了 Akka 的目的。在某些情况下,这是唯一的选择(主要是遗留代码),但每次有效地使用它会使您的代码完全阻塞,甚至可能是单线程的(取决于您的参与者代码)。在 Play 中尤其如此,它旨在异步执行所有操作,因此无需 Await.

重新考虑 actor 是否真的是您问题的最佳解决方案可能是个好主意。如果你想要的只是并行执行,那么 Futures 就简单多了。有些人在这种情况下仍然使用 actor,因为他们喜欢路由的抽象和简单性。我发现了一篇有趣的文章,详细描述了这一点:"Don't use Actors for concurrency"(另请阅读反对意见的评论)。

Actor System 需要每个 actor 的唯一名称(路径)。

路径格式如下akka://system@host:port/user/{your-actor-path}

例如

   val system = ActorSystem("hello")
   val myActor = system.actorOf(Props[MyActor], name ="myactor")
   //  myActor Path 
   // "akka://hello/user/myactor"  // purely local
   // "akka.tcp://hello@ip:port/user/myactor" // remote

在您的代码中,每次调用时都会创建 myActor。

这使得演员每次都走同一条路。

因此,不好的解决办法就是改代码如下

 val myActor = system.actorOf(Props[MyActor])      

如果您不为演员指定名称,那么演员系统将分配一个随机名称

myActor 每个函数调用的路径都不相同。

But, this is really bad solution, since myActor will not be destructed

(Actor is not terminated by GC)

如果一直调用函数,总有一天你的记忆力会space

所以,请在完成函数后 DESTRUCT myActor