设计 Actor 系统
学习设计并实现 Actor 层次结构、定义 Actor 行为,以及发送和接收消息。
设计 Actor 系统 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 3 节课。
设计 Actor 系统:简介
欢迎来到第 2 课!在上一课中,我们学习了 Akka Actor 模型的基础知识。现在,让我们深入了解 Akka Actor 系统的设计。
设计良好的 Actor 系统可靠、可扩展且易于维护。我们将探索如何组织 Actor、定义它们的行为,并使它们能够有效地通信。
理解 Actor 层次结构
Akka Actor 按树状层次结构组织,非常像文件系统。除了“根”Actor 之外,每个 Actor 都有一个父级。
- 父子关系:创建另一个 Actor 的 Actor 会成为它的父级。
- 监管:这一层次结构对于 Akka 的容错能力至关重要。父 Actor 负责监管其子 Actor(下一课将详细介绍这一点!)。
- 基于路径的寻址:每个 Actor 都有唯一的路径,反映其在层次结构中的位置,例如
/user/parentActor/childActor。
设置您的 ActorSystem
ActorSystem 是所有 Akka 应用程序的入口点。它管理 Actor 所需的资源,包括线程池和调度器。
每个应用程序只需创建一次 ActorSystem,然后使用它创建顶层 Actor。它就像整个 Actor 应用程序的容器。
尝试运行以下简单代码来创建 ActorSystem:
import akka.actor.ActorSystem
object AkkaSystemApp {
def main(args: Array[String]): Unit = {
// Create an ActorSystem with a unique name
val system = ActorSystem("MyFirstActorSystem")
println("ActorSystem created: " + system.name)
// Remember to terminate the system when done!
system.terminate()
}
}定义 Actor 行为
Actor 的行为决定了它如何响应不同的消息。在 Scala 中,您可以通过扩展 Actor 特质并实现 receive 方法来定义行为。
receive方法是一个偏函数,用于将传入的消息匹配到特定操作。- 每个 Actor 都会逐条、按顺序处理消息,从而确保其内部状态的线程安全。
ActorRef:Actor 的地址
您不会直接与 Actor 实例交互,而是向 ActorRef 发送消息。您可以将 ActorRef 理解为 Actor 的邮政地址。
- 它是系统中代表某个特定 Actor 的句柄。
- 发送到
ActorRef的消息会被放入该 Actor 的邮箱。 - 使用
actorOf创建 Actor 时,您会获得一个ActorRef。
向 Actor 发送消息
Actor 通信的主要方式是发送消息。最常见的消息发送方式是使用 !(读作“告知”)方法。
receiverActorRef ! "Your message here"
tell 方法是异步且发送后即忘的。它会发送消息,但不会等待回复。
让我们将创建 Actor 和向其发送消息结合起来:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
// 1. Define the actor's behavior
class GreeterActor extends Actor {
def receive = {
case "hello" => println(s"Greeter: Hello from ${self.path.name}!")
case msg: String => println(s"Greeter: Received message: '$msg'")
case _ => println("Greeter: Received something unexpected!")
}
}
object SimpleActorApp {
def main(args: Array[String]): Unit = {
// 2. Create the ActorSystem
val system = ActorSystem("GreeterSystem")
// 3. Create a top-level actor and get its ActorRef
val greeter: ActorRef = system.actorOf(Props[GreeterActor], "myGreeter")
// 4. Send messages to the actor using '!'
greeter ! "hello"
greeter ! "How are you doing today?"
greeter ! 123 // This will match the _ case
// Give actors time to process messages, then terminate
Thread.sleep(1000)
system.terminate()
}
}创建子 Actor
Actor 可以创建其他 Actor,从而形成我们讨论过的层次结构。父 Actor 使用 context.actorOf 创建子 Actor。
context.actorOf:由 Actor 用于创建其子 Actor。system.actorOf:由应用程序用于创建顶层(守护者)Actor。
创建子 Actor 有助于组织系统、委派任务并隔离故障。
父子通信
Actor 通过向彼此的 ActorRef 发送消息进行通信。子 Actor 可以通过 context.parent 获取其父 Actor 的 ActorRef。要回复消息的发送者,Actor 可以使用 sender()。
让我们看一个示例:父 Actor 创建子 Actor,告诉它执行工作,子 Actor 完成后报告结果:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
import scala.concurrent.ExecutionContext.Implicits.global
// Child Actor Definition: Does work and replies to sender
class ChildActor extends Actor {
def receive = {
case "work" =>
println(s"ChildActor (${self.path.name}): Doing work from ${sender().path.name}")
sender() ! "done" // Reply 'done' to the sender (parent)
}
}
// Parent Actor Definition: Creates child, sends work, receives reply
class ParentActor extends Actor {
// Create a child actor when the parent starts
val child: ActorRef = context.actorOf(Props[ChildActor], "myChild")
def receive = {
case "start" =>
println("ParentActor: Kicking off child's work.")
child ! "work" // Tell the child to do 'work'
case "done" =>
println(s"ParentActor: Child ${sender().path.name} reported 'done'.")
context.stop(child) // Stop the child actor
context.stop(self) // Stop the parent actor
}
}
object HierarchyApp {
def main(args: Array[String]): Unit = {
val system = ActorSystem("HierarchySystem")
val parent: ActorRef = system.actorOf(Props[ParentActor], "parentActor")
parent ! "start" // Start the interaction
// Wait for the system to terminate (actors will stop themselves)
system.whenTerminated.onComplete(_ => println("ActorSystem terminated."))
}
}优雅地停止 Actor
不再需要 Actor 时,应当优雅地停止它们,以释放资源。您可以通过以下几种方式停止 Actor:
context.stop(self):Actor 停止自身。context.stop(childRef):父 Actor 停止其一个子 Actor。system.stop(actorRef):用于顶层 Actor,不过通常情况下,您会停止整个系统。
Actor 停止时,会先处理邮箱中的所有消息,然后终止。其子 Actor 也会递归停止。
快速检查:Actor 设计
请思考以下 Akka Actor 代码片段。如果 MyParentActor 是初始“请求”消息的发送者,那么 MyChildActor 向创建它的父级 MyParentActor 发回消息的正确方式是什么?
回顾:设计 Actor 系统
做得很好!在本课中,我们介绍了设计 Akka Actor 系统的关键方面:
- Actor 按层次结构组织,这对于监管和系统结构至关重要。
ActorSystem是应用程序使用 Akka 的入口点。- 您可以使用
receive方法定义 Actor 的行为。 ActorRef是发送消息所用的地址。- Actor 使用
!(告知)方法进行异步通信。 - 父 Actor 使用
context.actorOf创建子 Actor,子 Actor 可以使用sender()回复。 - 可以使用
context.stop()优雅地停止 Actor。
接下来,我们将深入了解 Akka 强大的监管策略,以及如何优雅地处理故障!
常见问题解答
「设计 Actor 系统」课时是免费的吗?
是的 — 「设计 Actor 系统」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 3 节课。
「设计 Actor 系统」这节课中我会学到什么?
学习设计并实现 Actor 层次结构、定义 Actor 行为,以及发送和接收消息。 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。
「设计 Actor 系统」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Akka Actor 模型基础
- 设计 Actor 系统
- 监管与容错