本文主要讲解了Actor编程模型中的基本概念:Actor系统、Actor类、Actor实例、消息、邮箱、Actor引用、分配。
Actor模型目标
(1)彻底消除共享内存的需求
(2)解决与共享内存有关的问题,如数据争用与同步化
Actor模型处理消息
(1)可变状态被限定在Actor模型作用域内
(2)Actor模型收到消息的时候,可变状态有可能被修改
(3)Actor模型收到消息会以串行方式执行,一个接一个执行,这确保了Actor模型中的可变状态永远不会并发执行
Actor对象数量
(1)Actor对象的数量可以比处理器的数量高出多个数量级
(1)Actor模型可以决定何时向指定的Actor对象分配处理器时间,使得Actor对象能够处理消息
分布式程序设计
编写跨多台计算机和设备运行的应用程序的技术
位置透明性
(1)通过Actor模型可以在一台计算机的单进程中运行,也可以在多进程中运行
(2)可以编写在通过网络相连的多台计算机中运行
(3)程序员无需知道创建Actor对象和发送消息的具体位置
(4)无需了解网络中计算机之间的情况,来设计分布式系统
通过Akka框架介绍Actor模型
(1)声明Actor类并创建实例
(2)创建Actor状态模型并添加复杂的Actor行为
(3)处理Actor对象的层次结构和声明周期
(4)Actor对象消息通信中使用的多种传递方式
(5)使用内置的Actor监督机制实现错误恢复
(6)使用Actor模型创建透明的并发和分布式程序

解释:Actor1发送消息给Actor2的时候,会先将消息放入Actor2的邮箱(mailbox),Actor1可以等待消息,也可以不等待消息返回,Actor2从自己的邮箱中取出消息,进行处理。
Flink中就使用Akka来进行消息通信的
为了更好进行源码解析,这里来讲下RPC通信中用到的Akka框架
Actor模型类比
Actor系统理解成一个公司,公司有人员就是Actor,每个人有一个邮箱,每个Actor也有一个邮箱
Actor系统
Actor系统是一个具有层次结构的团体,在这个团体中每个角色都拥有通用的配置选项。
Actor系统职责:创建新的Actor对象、在Actor体系定位Actor对象、记录重要事件
Actor体系类比为:一个软件公司
Actor类
Actor类用于描述角色内部状态和角色处理消息的模板
通过同一Actor类可以创建多个Actor实例
Actor类类比为:软件公司中职位描述,测试工程师或开发工程师等等
Actor实例
Actor实例是在运行程序时存在的实体,Actor的实例只能接收消息。
Actor实例类比:实际干活的人
消息
消息是一种通信数据单位,Actor对象使用消息进行通信。在Akka中任何对象都可以别用作消息,Actor对象发送消息后会继续执行其它操作,而不会等待其它Actor对象收到消息后再开始新的工作
员工发送邮件后就去干别的事情了,员工不会等到对方收到邮件才干别的事情。
消息类比:邮件内容
邮箱
邮箱就像一块用于缓存消息的内存区域,每个Actor都有一块专属区域。同一时刻一个员工只能处理一个邮件,Actor实例同一时刻只能处理一条消息,邮箱在任意时刻都可能有多条消息。
邮箱:类比邮件的邮箱
Actor引用
Actor引用是一种对象,使用这个对象可以向指定的Actor实例发送消息。Actor引用会对程序员隐藏Actor实例的存储位置信息。
无论员工在做什么,在哪里,都可以收邮件
Actor引用类比:邮件的邮箱地址。
分配器
分配器是一种组件,它决定何时允许Actor实例处理消息,并为Actor实例分配相应的计算资源。
分配器确保了消息缓存区非空的Actor实例,最终由指定的线程运行,这些消息以串行的方式被处理。
分配器类比:公司规定回复邮件的规章制度。技术支持要求接到邮件马上回复,软件工程师要求可以不马上回复。
Actor创建和使用demo
package com.beenrun.akka.demoimport akka.actor.{Actor, Props}import akka.event.Logging/*** HelloActor 为Actor类* @param hello*/class HelloActor (val hello : String) extends Actor{val log = Logging(context.system,this)/*** 重写了receive方法* @return*/override def receive: Receive = {case `hello` =>log.info(s"Received a '$hello' ... $hello")case msg =>log.info(s"Unexpected message '$msg'")context.stop(self)}}object HelloActor{//伴生对象中使用重载的工厂方法创建HelloActor实例,下面两种方法创建都可以def props(hello: String) = Props(new HelloActor(hello))def propsAlt(hello: String) = Props(classOf[HelloActor],hello)}
创建实例并运行
package com.beenrun.akka.demoimport akka.actor.{ActorRef, ActorSystem}object ActorsCreate extends App {lazy val ourSystem = ActorSystem("OurExampleSystem")val hiActor:ActorRef = {ourSystem.actorOf(HelloActor.props("hi"),name = "greeter")}hiActor ! "hi"Thread.sleep(1000)hiActor ! "hola"Thread.sleep(1000)ourSystem.terminate()}/*** 运行结果* [INFO] [02/03/2023 07:53:58.600] [OurExampleSystem-akka.actor.default-dispatcher-2] [akka://OurExampleSystem/user/greeter] Received a 'hi' ... hi[INFO] [02/03/2023 07:53:59.600] [OurExampleSystem-akka.actor.default-dispatcher-3] [akka://OurExampleSystem/user/greeter] Unexpected message 'hola'*/
Akka中的receive方法源码
receive方法必须返回一个偏函数
trait Actor {// to make type Receive known in subclasses without importtype Receive = Actor.Receive/*** Scala API: This defines the initial actor behavior, it must return a partial function* with the actor logic.*///#receivedef receive: Actor.Receive}object Actor {/*** Type alias representing a Receive-expression for Akka Actors.*///#receive//这里声明一个别名,type Receive = PartialFunction[Any, Unit]}}
总结
本文主要讲解了Actor编程模型中的基本概念:Actor系统、Actor类、Actor实例、消息、邮箱、Actor引用、分配。并编写了第一个Demo实例。
奇迹的出现往往就在再坚持一下的时候!
感谢阅读。期待点赞、分享、关注。




