Akka:跨参与者实例共享状态

Posted

技术标签:

【中文标题】Akka:跨参与者实例共享状态【英文标题】:Akka: Sharing state across actor instances 【发布时间】:2015-07-10 17:01:41 【问题描述】:

我的MyProcessingActor actor 将使用实体 ID 上的 ConsistentHashingRouter 进行路由,这样在任何时候(跨多个线程)都可能有该 actor 的多个实例在处理中

actor 使用地图来执行一些计算逻辑。因此,2 个不同的 actor 实例可以同时读取和写入此地图。

在这些 Actor 实例之间共享地图似乎公然违反了 Actor 模型,即使它是 Java ConcurrentHashMap

处理此类问题的最佳选择是什么?我没有在 Akka 文档中看到它,除非我错过了。

我可以看到 2 个选项:

    MyMapManagerActor 的单个实例,它将管理对此地图的读/写。如果这是单线程的,那么实际上MyProcessingActor 也将是单线程的 使用 Akka STM - 我在最新版本的项目中没有看到这一点

还有哪些其他推荐的方法?

【问题讨论】:

我对 Akka 没有太多经验,但一直在研究它。您所描述的似乎确实与 Akka 打算适应的范式背道而驰。也许您可以在消息中传递路由映射并使其不可变。如果您要传递它,该地图也应该是不可变的。 你看过 Akka Agents 吗?他们可能会帮助解决此类问题doc.akka.io/docs/akka/snapshot/java/agents.html 【参考方案1】:

正如您在问题中所说,在参与者之间共享可变状态是一件非常糟糕的事情。我已经使用了您提到的两种方法(使用类似 MapManagerActor 和使用 Akka STM)并且两者都可以工作,尽管 MapManagerActor 方法对我来说感觉更好。就 MapManagerActor 而言,唯一被序列化的部分是对 Map 的实际读写,而不是计算本身,因此根据您的用例,您可能会发现并行化是足够的。

另一种选择是将地图本身替换为 Actor。你可以有一个父actor来管理子actor,并且每个地图条目都有一个该actor的子actor。如果您的密钥集是静态的,您可以在启动时预先创建所有子 Actor,例如,使用密钥(或其哈希码)作为 Actor 名称。然后您可以使用actorSelection 直接访问子Actor,如/user/parentActor/<key>。如果需要动态创建演员,最好向父演员询问特定的孩子,并让它回复ActorRef 给那个特定的孩子(如果需要,创建它)。比如:

override def receive = 
  case GetActor(key) =>
    context.children(key) match 
      case Some(ref) => sender ! GetActorReply(ref)
      case None => sender ! context.actorOf(ChildActor.props, key)
    
  

然后MyProcessingActor 可以使用该ActorRef 进行所有处理。

【讨论】:

【参考方案2】:

不幸的是,这在 Akka 中似乎是一件相当困难的事情。创建一个actor来管理对地图的访问被证明是相当麻烦的,而且最新版本似乎不支持STM。

因此,这里的解决方案是仔细选择ConsistentHashingRouter 的键,这样在读取和写入映射时就不会出现任何竞争条件。有问题的地图是ConcurrentHashMap

【讨论】:

【参考方案3】:

当一个 Actor 实际运行时,它会作为 Runnable 在某个 Executor 上运行。顺序运行一组协作的 Actor 的技巧是为每组这样的 Actor 提供一个专用的串行执行器 - 请参阅 my answer to the corresponding question。

【讨论】:

【参考方案4】:

如果地图是 Actor 实例上的一个字段,那么就会有两个地图,不会出现跨线程问题。如果地图是共享的但只读的,那么你仍然可以。如果地图是共享的并且两个参与者都向它写入,那么您肯定需要使用 ConcurrentHashMap 进行锁定。

【讨论】:

您在这里并没有真正回答问题,只是重复了问题已经说明的内容。 “还有哪些其他推荐的方法?” 没错。我要指出的是,如果不共享地图,则不会发生冲突。因此,不需要替代方法。如果要共享地图,那么 ConcurrentMap 将是正确的选择。 这些是共享的:因此,2 个不同的 actor 实例可以同时读取和写入此地图。

以上是关于Akka:跨参与者实例共享状态的主要内容,如果未能解决你的问题,请参考以下文章

Akka 有限状态机实例

Flutter之跨组件共享状态Provider原理剖析

Flutter 功能型组件:跨组件状态共享(Provider)

Flutter功能型组件之跨组件状态共享

我可以在 React 中跨多个树共享一个组件实例吗?

Akka - 你应该创建多少个actor实例?