【问题标题】:Global variable within akka actor system in ScalaScala中akka演员系统中的全局变量
【发布时间】:2016-12-19 15:07:29
【问题描述】:

我目前在我的 Scala 代码中使用 akka Actor 系统。我有一个父演员和一个儿童演员。我想要做的是在父演员处启动一个列表并让子演员:

i)生成新元素并将它们发送给父actor,父actor会将它们附加到列表中。 ii) 随时访问列表元素。

我怎样才能实现第二(ii)部分?

【问题讨论】:

    标签: scala akka actor


    【解决方案1】:

    必须使用消息传递。在两个参与者之间共享任何类型的可变状态都违反了 Akka 提供的所有保证。

    或者,您可以在您的子actor和父actor之间共享一个Agent,这将使列表的更新线性化,同时允许同步读取。

    【讨论】:

    【解决方案2】:

    您可以选择父母可以回复的特定消息,以披露其内部状态。请参阅下面的示例:

      import scala.collection.immutable.Queue
    
      class Parent extends Actor {
        import Parent._
    
        // TODO: start children here
    
        override def receive: Receive = receiveElements(Queue.empty[Element])
    
        def receiveElements(acc: Queue[Element]): Receive = {
          case e@Element => context.become(receiveElements(acc :+ e))
          case GetElements => sender ! acc
        }
      }
    
      object Parent {
        case class Element(s: String)
        case object GetElements
      }
    

    请注意,通过将 var queue 保留在 Parent 内部而不是使用 context.become+recursion 可以实现相同的行为。

    此外,不设计刷新队列的方法可能会导致 OOME。

    【讨论】:

    • 问题是我希望在运行时访问这个列表。我希望我的子演员接收“开始”消息,运行一个函数,并且在这个函数内部可以访问列表。我不想等待第一条消息被处理,然后再处理第二条消息。
    • 简单地说:不可能。这违反了 Akka 的所有原则。
    【解决方案3】:

    好吧,我设法找到了解决方案。

    如果您在父 Actor 内创建一个变量并将其作为构造参数传递给子 Actor ,则如果您不替换它,则此变量中的每个更改都是可见的。我会在一个错误的例子之后用一个正确的例子来解释。

    class ParentActor(/*constructors here*/) extends Actor{
       val list =ListBuffer[Int](1,2)
       child = new ChildActor(list //+other constructors)
    
       list=ListBuffer[Int](1,2,3) // **wrong** child will see list=List(1,2)
       list+=3         // **right**  child will see list=List(1,2,3) as wanted
    

    }

    class ChildActor(list : ListBuffer[Int] /*++ otherconstructors here*/) extends Actor{
    
           list=ListBuffer[Int](1,2,3,4) // **wrong** parent will see list=List(1,2,3)
           list+=4           // **right**  child will see list=List(1,2,3,4) as wanted
    

    }

    【讨论】:

    • 此解决方案是 Akka 反模式,不推荐使用。首先,请注意ListBuffer 不是线程安全的集合。其次,即使选择线程安全的集合也会违反位置透明性——因为序列化是不可能的。在这里进一步阅读manuel.bernhardt.io/2016/08/02/…
    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 2019-04-23
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 2013-10-14
    相关资源
    最近更新 更多