Actor 之间的相互通信 | 学习笔记

简介: 快速学习 Actor 之间的相互通信

开发者学堂课程【Scala 核心编程 - 进阶Actor 之间的相互通信学习笔记,与课程紧密连接,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/610/detail/9116


Actor 之间的相互通信


内容介绍:

一、上节小结和示意图

二、Actor 间的通讯

三、代码实现


一、上节小结和示意图

1.当程序执行 aActorRef= actorFactory.actorOf(Props[AActor], "aActor"),会完成如下任务[这是非常重要的方法]

1)actorFactory 是 ActorSystem("ActorFactory") 这样创建的。

2)这里 Props[AActor] 会使用反射机制,创建一个 AActor 对象,如果是actorFactory.actorOf(Props(new AActor(bActorRef)), "aActorRef") 形式,就是使用 new 的方式创建一个 AActor 对象,注意 Props() 是小括号。

3)会创建一个 AActor 对象的代理对象 aActorRef ,使用 aActorRef 才能发送消息

4)会在底层创建  Dispather Message,是一个线程池,用于分发消息,消息是发送到对应的 Actor 的 MailBox

5)会在底层创AActor 的 MailBox 对象,该对象是一个队列,可接收 Dispatcher Message发送的消息(如果消息很多,会形成队列,消息队列形成后,推送消息时是一个一个消息推送的)

6) MailBox 实现了 Runnable 接口,是一个线程,一直运行并调用 Actor 的 receive 方法,

因此当 Dispather 发送消息到 MailBox 时,Actor 在 receive 方法就可以得到信息.

7) aActorRef ! "hello",表示把hello消息发送到 AActor 的 mailbox 通过Dispatcher Message转发)

2.一个示意图的说明

image.png


二、Actor 间的通讯

1.应用实例需求

1)编写2个 Actor,分别是 AActor 和 BActor

2)AActor 和 BActor 之间可以相互发送消息

示意图如下

image.png

3)加强对Actor传递消息机制的理解。

2.两个 Actor 的通讯录机制原理图

image.png

3.A Actor 如何发消息到 B Actor

首先,A Actor 要给自己发消息,A Actor 作为主动发起者,必须先要持有 B Actor B ActorRef,即创建 A Actor 时,首先要有 B Actor 的引用。

因为A Actor 发消息时肯定是在 receive 中发消息仍然发给 Dispatcher Message Dispatcher Message 会将消息发送到B Actor 的MailBox ,B Actor 的MailBox 得到消息后推送给B Actor 的 receive() 方法,receive 方法将该消息自动通过 sender() 方法得到发送过来的 Actor 的引用,sender() 方法把这条消息回送给 A Actor 的MailBox(也是经过 Dispatcher Message),然后 A Actor 的 MailBox 一直运行将消息推送给 A Actor 的 receive 方法,receive 方法接收这条消息后又给 B Actor 回消息,消息就是这样相互回应。


三、代码实现

/*新建三个文件

分别为 AActor、BBctor、ActorGame(调用前两者)

因为 actor 主要取决于主动发起消息,主动发起的一定要持有对方的引用才能发起,前面说到 A Actor 先发消息,所以先写 AActor 文件中的代码

*/

1.先写 AActor 文件中的代码

import akka . actor . { Actor,ActorRef}

class AActor(actorRef: ActorRef ) extends Actor {

va1 bActorRef: ActorRef = actorRef

override def receive: Receive = {

case "start" =>{    //接收一个信息,开始跑程序

println( "AActor 出招了, start ok")

self ! “我打”   //发给自己

}

case"我打"=>{  //接收到“我打“,输出下面的一句话

//BActor 发出消息

//这里需要持有BActor的引用(BActorRef)

println( "AActor(黄飞鸿)厉害 看我佛山无影脚")

bActorRef ! "我打”    //给BActor发出消息

}

}

}

2.接下来在 BBctor 中写

import akka. actor.Actor

class BActor extends Actor{

override def receive : Receive = {

case “我打”=>{   //如果接收到“我打!“

printLn( "BActor(乔峰) 挺猛 看我降龙十八掌")

//通过sender()可以获取到发消息的actor 的 ref

sender() ! “我打"  //!是一种方法的重载

}

}

}

3.最后在 ActorGame 中写(如何调用)

import akka . actor . {ActorRef, Actorsystem,Props}

object ActorGame extends App {

//创建 Actorsystem

val actorfactory = Actorsystem ( "actorfactory")

//先创建 BActor 引用/代理

//可以用反射机制创建val bActorRef: ActorRef = actorfactory.actorof( Props[BActor],"bActor")

//创建 AActor 的引用val aActorRef: ActorRef = actorfactory.actorof(Props(new AActor(bActorRef)),"aActor"')

//aActor 出

aActorRef ! "start"  //也可以直接发出“我打“

}

运行结果为:

image.png

发现输出结果太快,看不出效果

所以可以让其休眠一会,将AActor 文件添加部分代码如下:

case"我打"=>{  

println( "AActor(黄飞鸿)厉害 看我佛山无影脚")

Thread.sleep(1000)

bActorRef ! "我打”    

}

同样,将AActor 文件添加部分代码如下:

case “我打”=>{  

printLn( "BActor(乔峰) 挺猛 看我降龙十八掌")

Thread.sleep(1000)

sender() ! “我打"  

}

4.如何理解 Actor  receive 的方法被调用?

1)每个 Actor 对应 MailBox

2MailBoX 实现了 Runnable 接口,处于运行的状态

3)当有消息到达 MailBox ,就会去调用 Actor 的 receive 方法,将消息推送给 receivel

在上面的程序中,发现没有显示的调用,receive 方法能被用是因为其底层有一个 MailBox 在不停的做其工作,消息一被接收到就推送,这种机制解决了同步问题,有消息就处理,没有消息也不产生影响,并且不需要关心消息到达的途径如何和消息何时回应。

相关文章
|
边缘计算 JSON 物联网
解锁业务灵活性:RuleGo规则引擎的高效解耦与实时响应秘籍
RuleGo是一个基于Go语言的轻量级、高性能规则引擎,旨在通过动态规则链和组件化设计,简化复杂系统的业务逻辑管理和实时响应。
解锁业务灵活性:RuleGo规则引擎的高效解耦与实时响应秘籍
|
4月前
|
消息中间件 SQL 关系型数据库
什么是实时数据同步?纯干货解读!
在数据处理中,数据同步问题常常导致报表不准、决策滞后。本文深入解析实时数据同步的重要性与实现方法,帮助你解决80%的同步难题,提升数据效率与业务响应速度。
什么是实时数据同步?纯干货解读!
|
12月前
|
存储 NoSQL MongoDB
.NET MongoDB数据仓储和工作单元模式封装
.NET MongoDB数据仓储和工作单元模式封装
206 15
|
10月前
|
SQL 存储 关系型数据库
MySQL主从复制 —— 作用、原理、数据一致性,异步复制、半同步复制、组复制
MySQL主从复制 作用、原理—主库线程、I/O线程、SQL线程;主从同步要求,主从延迟原因及解决方案;数据一致性,异步复制、半同步复制、组复制
1129 11
|
JSON 资源调度 网络性能优化
vue3中使用mqtt数据传输(封装)
vue3中使用mqtt数据传输(封装)
646 4
C#学习virtual(虚拟的)和abstract(抽象的)的区别
C#学习virtual(虚拟的)和abstract(抽象的)的区别
348 0
在遭遇勒索软件攻击后是支付赎金还是不支付赎金?
在遭遇勒索软件攻击后是支付赎金还是不支付赎金?
|
PyTorch 算法框架/工具 机器学习/深度学习
PyTorch 2.2 中文官方教程(十七)(2)
PyTorch 2.2 中文官方教程(十七)
343 1
PyTorch 2.2 中文官方教程(十七)(2)
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
536 1
|
NoSQL Linux Redis
Centos7 安装和配置 Redis 5 教程
在Centos上安装Redis 5,如果是 Centos8,那么 yum 仓库中默认的 redis 版本就是 5,直接 yum install 即可。
1517 0