【发布时间】:2021-03-29 16:03:23
【问题描述】:
我曾经做过 Akka Actor(非类型化),最近开始编写 Akka 类型化 Actor,发现有两种实现方式,一种是功能方式,另一种是面向对象方式(类似于旧的方式)。
我对以函数式和面向对象的方式理解状态封装很感兴趣。所以写了一个函数式的方法和一个面向对象的类。
功能方式:
def webSocketConnections(l: List[ActorRef[Message]] = List.empty): Behavior[WebSocketMsg] = {
Behaviors.receive[WebSocketMsg] {
(context, message) => {
message match {
case Model.UserAdded(actorRef) => webSocketConnections(actorRef :: l)
case Model.BroadcastToAll(msg) =>
context.spawnAnonymous(broadCastActorBehaviour) ! Broadcast(l, msg)
Behaviors.same
}
}
}
}
面向对象的方式
class WebSocketConnectionMaintainer(actorContext: ActorContext[WebSocketMsg]) extends
AbstractBehavior[WebSocketMsg](actorContext) {
private var actorRefL: List[ActorRef[Message]] = List.empty
override def onMessage(msg: WebSocketMsg): Behavior[WebSocketMsg] = {
msg match {
case Model.UserAdded(actorRef) =>
actorRefL = actorRef :: actorRefL
Behaviors.same
case Model.BroadcastToAll(msg) =>
actorContext.spawnAnonymous(broadCastActorBehaviour) ! Broadcast(actorRefL, msg)
Behaviors.same
}
}
}
如果你观察这两种情况,在函数式的情况下,状态被封装为一个参数,不确定它是否会在堆栈安全方面出现问题,因为它可能会由于堆栈溢出错误而崩溃很多次打电话对吗?
但是如果你观察面向对象的方式,它只是直接改变列表,不会导致任何堆栈溢出问题。
我发现的另一个问题是,我只能使用context.spawn 来生成函数式actor,但在面向对象的情况下,我需要一个特定类型的上下文。
如果我想同时创建函数式和面向对象的actor怎么办?
【问题讨论】:
-
一般来说,在actor内部拥有可变状态是好的,因为actor是线程安全的。但是如果你有一个未来的回调函数内部的可变状态,你可能会破坏 Actor 封装,就像这里显示的那样 (stackoverflow.com/a/23908461/2096986)。所以这就是为什么最好通过实现函数式的方式来拥有无状态的参与者
-
@Felipe,正确,我知道它是线程安全的,但我说的是堆栈安全和产生一个actor
-
stack overflow是什么意思?你是说万一你尝试生成很多儿童演员,在某些时候会崩溃? -
不@Felipe,如果是演员的功能方式,行为不会被自己调用并且会导致堆栈溢出吗?
标签: scala akka actor akka-typed