如何在 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
}
}
如何在 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
}
}