怎么给演员起名字?
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 是否真的是您问题的最佳解决方案可能是个好主意。如果你想要的只是并行执行,那么 Future
s 就简单多了。有些人在这种情况下仍然使用 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
。
我的 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 是否真的是您问题的最佳解决方案可能是个好主意。如果你想要的只是并行执行,那么 Future
s 就简单多了。有些人在这种情况下仍然使用 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
。