如何在 Akka Actor 对象字段中存储数据?

How to store data in Akka Actor Object fields?

如何在 Actor 对象中使用可变 Map 来根据消息存储值? 我的代码

object TestActor {
   final case class Command()
   private val mmap: mutable.Map[Int,Map[Int,Int]] = mutable.Map[Int,Map[Int,Int]]()
   
   def apply(): Behavior[Command] = Behaviors.receive {
       case (context, Command()) => 
            mmap += (1 -> (2 -> 3)) 
            context.log.info(nmap)
   }
}

这会导致问题,因为 mmap 是静态的,因为它是 Scala 对象中的一个字段。所以当多个线程向映射中添加一些值时,会产生奇怪的值。因为我仍然需要使用类型化的 akka 演员,有没有办法在对象中有一个字段(或以其他方式)让我仍然可以使用对象来表示使用 akka.typed 的演员并且仍然有 TestActor 演员不共享的字段?

在 Akka Typed 的函数式 API 中(本示例使用),典型的方法是遵循以下几行:

object TestActor {
  final case class Command()

  def apply(): Behavior[Command] =
    fromMap(mutable.Map.empty)

  private def fromMap(mmap: mutable.Map[Int, Map[Int, Int]]): Behavior[Command] =
    Behaviors.receive {
      case (context, Command()) =>
        mmap += (1 -> Map(2 -> 3))
        context.log.info(mmap)
        Behaviors.same
    }
}

在这里,object 基本上只是一个模块,该对象的字段最好被认为是全局变量。

请注意,还有一个 object-oriented API 用于定义类型化角色,在 Scala 中为:

object TestActor {
  final case class Command()

  def apply(): Behavior[TestActor.Command] =
    Behaviors.setup { context =>
      new TestActor(context)
    }
}

class TestActor(context: ActorContext[TestActor.Command]) extends AbstractBehavior[TestActor.Command](context) {
  val mmap: mutable.Map[Int, Map[Int, Int]] = mutable.Map.empty

  def onMessage(msg: TestActor.Command): Behavior[TestActor.Command] = {
    mmap += (1 -> Map(2, 3))
    context.log.info(mmap)
    this
  }
}

值得注意的是,在 Akka 中,拥有 var 的不可变数据(即包含不可变值的可变容器)通常比 val 的可变数据(即包含可变的不可变容器)更好值),因为这可以为演员(包括另一个演员)之外的事物公开一个渠道,以“从演员下面拉出地毯”。

在函数 API 中,这通常采用如下形式:

object TestActor {
  final case class Command()

  def apply(): Behavior[Command] =
    fromMap(Map.empty)

  private def fromMap(map: Map[Int, Map[Int, Int]]): Behavior[Command] =
    Behaviors.receive {
      case (context, Command()) =>
        val nextMap = map + (1 -> Map(2 -> 3))
        context.log.info(nextMap)
        withMap(nextMap)
    }
}

在 OO Scala 中 API:

// TestActor companion object is as before

class TestActor(context: ActorContext[TestActor.Command]) extends AbstractBehavior[TestActor.Command](context) {
  var map: Map[Int, Map[Int, Int]] = Map.empty

  def onMessage(msg: TestActor.Command): Behavior[TestActor.Command] = {
    map = map + (1 -> Map(2 -> 3))
    context.log.info(map)
    this
  }
}