我想创建可以从文件系统提供资源的actor。理想情况下[1]我想为每个目录和每个文件都有一个actor。但我不想创建整个actor树层次结构,因为我希望尽可能地节省内存和资源。
据我了解,只有在其父级存在的情况下才能创建一个actor。懒惰地创建这些层次结构的最佳方法是什么?是否有一个钩子可以用来捕获失败并动态创建actor层次结构,并且这样做有效吗?
这样我就可以将fetch
,update
,delete
,...消息发送给演员,而akka演员系统可以处理同步问题。然后可以将其扩展到更复杂的演员行为,稍后将使用虚拟文件等概念......
我能想到的一些可能的解决方案:
context.actorFor(path)
如果它返回死信邮箱,请尝试创建actor层次结构。这听起来不是一个好的解决方案。getOrCreateChild
方法将其转发给其子节点。但这可能效率低下吗? (或者这就是akka本身在引擎盖下做的......(我应该看看))[1]我不确定这是否理想,但我认为我应该首先尝试这种方法。另一种方法是为每个目录创建一个actor并将其存储在哈希映射中。
答案 0 :(得分:2)
首先,演员非常轻量级。您可以在JVM中运行数百万,并且演员本身的占用空间非常小。显然,如果演员有一些可以大记忆的自定义状态,这会发生变化,但演员本身的占地面积非常小。
现在,如果你仍想懒洋洋地实现它们,一种方法可能是拥有一个接收所有初始调用的文件或文件夹主actor。该actor检查系统以查看是否存在一个actor,以便为请求所针对的任何文件夹或文件提供请求。如果没有,主设备会创建它,然后将消息转发给它。如果是这样,它只是将消息转发给它。无需在内存中保留哈希映射,因为ActorSystem
本身将为您保留所有ActorRefs
,并为您提供查找它们的方法。您只需要一个将文件名/路径等同于actor名称的方法。主人的简化示例可能如下所示:
case class Fetch(path:String)
class FileMaster extends Actor{
def receive = {
case msg @ Fetch(path) =>
val ref = lazyFindActor[FileHandler](path)
ref.forward(msg)
}
def lazyFindActor[T <: Actor: Manifest](name:String) = {
val ref = context.actorFor(name)
if (ref == context.system.deadLetters){
context.actorOf(Props[T], name)
}
else{
ref
}
}
}
所有lazyFindActor
都会检查路径的actor是否已经创建并启动。如果是这样,它就转发给它。如果不是(并且它与deadLetters
比较不幸地做出这个决定,我没有看到更好的方法来检查一个演员是否存在),它在主人的监督下创建一个然后转发给它。下次使用相同的路径时,它将使用预先存在的Actor
。
您可能需要做一些工作,从文件路径语法转换为可用于演员名称的东西(因为akka已经使用分层文件路径,如演员路径的结构),但我不是100%确定那一个。只是想向你抛出一个高级概念,看看这是否是你想要的。