将对象用作AKKA演员有什么危险?

时间:2018-09-07 11:59:59

标签: scala akka

在下面的代码中,尽管我是一个对象,但我正在使用AKKA actor 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
          }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

此“模式”引起的一个直接问题是:如果将Actor两次添加到actorSystem会发生什么:

actorSystem.actorOf(Props(MonitorActor))
actorSystem.actorOf(Props(MonitorActor))

这不是一个小问题。在大型代码库中,可以包含多个Actor的文件/包,因此,如果只是偶然,可能会出现上述情况。

充其量,每个SomeEvent被完全相同的逻辑处理两次。在最坏的情况下,您会遇到isEnough令人讨厌的比赛条件。因此,让我们假设最好的情况。

即使在最佳情况下,每个SomeEvent也将由完全相同的逻辑进行处理。在问题的示例中这还不错,因为membersSet。但是,如果它是List,您将开始两次插入同一事件。

另一个问题是必须保护自己免受涉及members的比赛条件的影响。 members成为AtomicReference的一个很好的理由是要解决两个“独立”参与者试图同时访问members的情况。但这违背了Actor模型的全部目的。来自original 1973 formalism(重点是我):

  

关于控制结构,体系结构是通用的,并且确实   不需要或不需要goto,interrupt或信号量原语

akka documentation's introduction(强调我的名字)中可以找到类似的描述:

  

Actor模型为写作提供了更高层次的抽象   并发和分布式系统。 减轻开发人员的负担   不得不处理显式锁定和线程管理,   更容易编写正确的并发和并行系统。

因此,我们已经有效地破坏了Actor模型框架,而我们所要做的只是不必调用构造函数。将问题的示例代码与“ preferable”实现进行对比:

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中的所有逻辑和功能。