scala - 使用对象作为 AKKA 演员有什么危险?
问题描述
在下面的代码中,我使用的是 AKKA 演员 MonitorActor,即使它是一个对象。我从来没有在生产代码中看到过这种模式,尽管它似乎运行良好。
由于使用对象作为 Actor,以下代码是否存在并发问题?
这里是否有任何与 AKKA 演员相关的“陷阱”?
case class SomeEvent(member: String)
class Example(eventBus: EventBus)(implicit actorSystem: ActorSystem) {
val members: AtomicReference[Set[String]] = new AtomicReference(Set())
actorSystem.actorOf(Props(MonitorActor))
private object MonitorActor extends Actor {
eventBus.subscribe(classOf[SomeEvent])
var isEnough = false
override def receive: Receive = {
case SomeEvent(member: String) =>
val newMembers = members.updateAndGet(_ + member)
if (newMembers.size >= 10) {
isEnough = true
}
}
}
}
解决方案
这种“模式”引起的一个直接问题是:如果将Actor
加到actorSystem
两次会发生什么:
actorSystem.actorOf(Props(MonitorActor))
actorSystem.actorOf(Props(MonitorActor))
这不是一个微不足道的问题。在大型代码库中,可能存在多个文件/包,其中一个 Actor 被具体化,因此上述情况可能只是偶然出现。
充其量,每个SomeEvent
都由完全相同的逻辑处理两次。在最坏的情况下,您将陷入令人讨厌的比赛条件isEnough
。所以让我们假设最好的情况。
即使在最好的情况下,每个 SomeEvent 都将由完全相同的逻辑处理。members
这在问题的示例中还不错,因为Set
. 但是,如果它是 a List
,您将开始获得同一事件的双重插入。
另一个问题是必须保护自己免受涉及members
. members
成为 an 的一个很好的理由AtomicReference
是解决两个“独立”Actor 试图同时访问members
的情况。但这违背了 Actor 模型的全部目的。从最初的 1973 年形式主义(强调我的):
该体系结构在控制结构方面是通用的,不需要或不需要 goto、interrupt 或semaphore 原语。
在akka 文档的介绍中可以找到类似的描述(强调我的):
Actor 模型为编写并发和分布式系统提供了更高级别的抽象。它使开发人员不必处理显式锁定和线程管理,从而更容易编写正确的并发和并行系统。
所以我们有效地打破了 Actor 模型框架,我们得到的只是不必调用构造函数。将问题的示例代码与“首选”实现进行对比:
class MonitorActor() extends Actor {
val members: Set[String] = Set.empty[String]
eventBus.subscribe(classOf[SomeEvent])
var isEnough = false
override def receive: Receive = {
case SomeEvent(member: String) => {
members add member
isEnough = members.size >= 10
}
}
}
现在,开发人员不必担心信号量、竞争条件、线程争用……Actor 中的所有逻辑和功能都可以从串行的角度来理解。
推荐阅读
- c++ - C++ lambda 按值捕获语义和允许的优化
- python - 在 Python 中实现广义生日悖论
- python - Python:将许多具有共享键的字典(在 JSON 中)连接到一个大字典中
- c++ - 编译时是否需要动态库
- node.js - 从 Node JS App Engine server.js 文件(标准环境)连接到 GCloud SQL 2
- java - 常规和 Spring 抽象的 Ignite 事务在手动重新连接后以 IllegalStateException 失败,clientReconnectDisabled 为 true
- android - 跳过密码或图案屏幕,直接打开应用程序
- java - 如何在使用 dom4j 迭代器时消除未经检查的赋值警告
- database - 避免 Postgres 表中有超过 1500 列
- python - python中列中的模式匹配