Akka actors 之间的数据共享
Data sharing between Akka actors
基于这个问题Data sharing in Akka我实现了一个简单的 akka 层次结构来在两个参与者之间共享数据:
package playground
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
case object GetFromDb
case object GetList
case object ProcessList
class ParentActor extends Actor {
var fromDb: List[Int] = List()
def receive = {
case GetFromDb =>
// query the database and replace fromDb with a new list
fromDb = List(1,2,3)
case GetList =>
sender() ! fromDb
}
}
class ChildActor(parent: ActorRef) extends Actor {
def receive = {
case ProcessList =>
// get the list from the parent
parent ! GetList
case fromDb: List[Int] =>
fromDb.foreach(println)
}
}
object AkkaDataSharingDriver extends App {
val system: ActorSystem = ActorSystem("as")
implicit val ec = system.dispatcher
val parentActorRef: ActorRef = system.actorOf(Props(new ParentActor()))
val childActorRef: ActorRef = system.actorOf(Props(new ChildActor(parentActorRef)))
parentActorRef ! GetFromDb
parentActorRef ! GetList
childActorRef ! ProcessList
}
列表值 1、2、3 被打印出来,因此消息 fromDb
被发送到 ChildActor
,导致调用此 foreach
:
case fromDb: List[Int] =>
fromDb.foreach(println)
但是由于从未明确发送带有 fromDb
的消息,导致
的原因
fromDb.foreach(println)
要调用?它是否以某种方式隐式发送?
child/parent 命名相当混乱,因为此代码中没有 parent/child 关系。最好将它们称为 DbProvider 和 DbClient。
顺序是这样的:
- 应用发送
ProcessList
给儿童演员 (childActorRef ! ProcessList
)
- 子actor发送
GetList
给父actor(parent ! GetList
)
- 父 actor 使用 db (
sender() ! fromDb
) 回复子 actor
- 子actor收到db并打印出来
请注意,此代码中存在竞争条件,理论上 db 可能是 List()
而不是 List(1,2,3)
。
Akka 中唯一的传递保证是从一个 actor 发送到同一 actor 的两条消息将按照它们发送的顺序进行处理。否则消息可以按任何顺序处理,特别是通过第三方发送的消息可以超过直接发送的消息。
在这种情况下,ProcessList
消息可以由 ChildActor
处理,结果 GetList
消息可以在 [=21= 之前由 ParentActor
处理] 来自应用程序的消息由 ParentActor
处理。如果发生这种情况,对 GetList
的回复将包含默认的 DB 值。
基于这个问题Data sharing in Akka我实现了一个简单的 akka 层次结构来在两个参与者之间共享数据:
package playground
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
case object GetFromDb
case object GetList
case object ProcessList
class ParentActor extends Actor {
var fromDb: List[Int] = List()
def receive = {
case GetFromDb =>
// query the database and replace fromDb with a new list
fromDb = List(1,2,3)
case GetList =>
sender() ! fromDb
}
}
class ChildActor(parent: ActorRef) extends Actor {
def receive = {
case ProcessList =>
// get the list from the parent
parent ! GetList
case fromDb: List[Int] =>
fromDb.foreach(println)
}
}
object AkkaDataSharingDriver extends App {
val system: ActorSystem = ActorSystem("as")
implicit val ec = system.dispatcher
val parentActorRef: ActorRef = system.actorOf(Props(new ParentActor()))
val childActorRef: ActorRef = system.actorOf(Props(new ChildActor(parentActorRef)))
parentActorRef ! GetFromDb
parentActorRef ! GetList
childActorRef ! ProcessList
}
列表值 1、2、3 被打印出来,因此消息 fromDb
被发送到 ChildActor
,导致调用此 foreach
:
case fromDb: List[Int] =>
fromDb.foreach(println)
但是由于从未明确发送带有 fromDb
的消息,导致
fromDb.foreach(println)
要调用?它是否以某种方式隐式发送?
child/parent 命名相当混乱,因为此代码中没有 parent/child 关系。最好将它们称为 DbProvider 和 DbClient。
顺序是这样的:
- 应用发送
ProcessList
给儿童演员 (childActorRef ! ProcessList
) - 子actor发送
GetList
给父actor(parent ! GetList
) - 父 actor 使用 db (
sender() ! fromDb
) 回复子 actor
- 子actor收到db并打印出来
请注意,此代码中存在竞争条件,理论上 db 可能是 List()
而不是 List(1,2,3)
。
Akka 中唯一的传递保证是从一个 actor 发送到同一 actor 的两条消息将按照它们发送的顺序进行处理。否则消息可以按任何顺序处理,特别是通过第三方发送的消息可以超过直接发送的消息。
在这种情况下,ProcessList
消息可以由 ChildActor
处理,结果 GetList
消息可以在 [=21= 之前由 ParentActor
处理] 来自应用程序的消息由 ParentActor
处理。如果发生这种情况,对 GetList
的回复将包含默认的 DB 值。