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 在不停的做其工作,消息一被接收到就推送,这种机制解决了同步问题,有消息就处理,没有消息也不产生影响,并且不需要关心消息到达的途径如何和消息何时回应。

相关文章
|
8天前
|
存储 编解码 网络协议
计算机与通信的关系
计算机与通信的关系
11 0
|
2月前
|
开发框架 .NET C#
浅谈c和c++和c#之间的关系
浅谈c和c++和c#之间的关系
26 0
|
10月前
|
安全 Java C++
Java线程之间通信方式
Java线程之间通信方式
82 0
|
11月前
|
存储 JavaScript
02-TsVSJs之间的区别
02-TsVSJs之间的区别
44 0
|
存储 Web App开发 前端开发
💞💞💞SharedWorker 让你多个页面相互通信
SharedWorker 是一个新的Web Worker API,它允许你在多个页面之间共享一个Worker。 SharedWorker 代表一种特定类型的Worker,可以在多个浏览器上下文中运行,
162 0
💞💞💞SharedWorker 让你多个页面相互通信
使用一个例子探析:生产者消费者在多线程之间的通信的使用
使用一个例子探析:生产者消费者在多线程之间的通信的使用
96 0
|
Java
线程之间的通信(二)
线程之间的通信(二)
106 0
线程之间的通信(一)
线程之间的通信(一)
109 0
|
uml
类和类之间的关系(1)
类和类之间的关系(1)
102 0
类和类之间的关系(1)