Akka之actor模型
来源:互联网 发布:编程错误error 编辑:程序博客网 时间:2024/05/16 09:59
一 定义Actor
importakka.actor.{Props, ActorSystem, Actor}
import akka.actor.Actor.Receive
import akka.event.Logging
/** 通过扩展Actor并实现receive方法来定义Actor*/
class MyActorextends Actor{
//获取LoggingAdapter,用于日志输出
val log = Logging(context.system,this)
def receive = {
case "test"=> log.info("Received Test")
case _ => log.info("Received Unknown Message")
}
}
object MyActor extends App {
/*ActorSystem 用于创建维护Actor*/
val system = ActorSystem("MyActorSystem")
/*返回ActorSystem的LoggingAdpater*/
val systemLog= system.log
/*通过ActorSystem#actorOf创建MyActor指定名称为myactor*/
val myactor = system.actorOf(Props[MyActor],name="myactor")
systemLog.info("准备向myactor发送消息")
/*向myactor发送消息*/
myactor !"test"
myactor !"123"
/*关闭ActorSystem,停止程序的运行*/
system.shutdown()
}
二 ActorSystem
ActorSystem的只要职责:
# 创建Actor 和 ActorRef
# 返回Actor Ref
# 拦截消息,并把它发到邮箱(临时存储消息的地方)
创建ActorRef
system.actorOf(Props[MyActor],name="myactor")
我们可以在Props[Actor]放入一个Actor类型,也可以放入一一个Actor引用,但是这种是不推荐的
使用ActorRef对象可以进行消息的发送等操作
三 2种创建Actor的方式
3.1 ActorSystem 创建Actor
val system = ActorSystem("mySystem")
val myActor = system.actorOf(Props[MyActor],"myactor2")
通过ActorSystem创建的Actor是顶级Actor,在Akka框架中,每一个Akka应用程序都会有一个守卫Actor(guardian)user,所有通过system.actorOf工厂方法创建的Actor都是user的子Actor,也是整Akka程序的顶级Actor
3.2 通过context创建Actor
我们可以通过Actor上下文创建子Actor,使得父Actor拥有管理子Actor的能力
import akka.actor.Actor.Receiveimport akka.actor.{ActorLogging,Actor,Props}class ContextActor extends Actor with ActorLogging{ val childActor = context.actorOf(Props[MyActor], name = "ChildActor") def receive: Receive = { case msg => childActor !msg; log.info("Received "+msg) }}
object MyActor extends App { /*ActorSystem 用于创建维护Actor*/ val system = ActorSystem("MyActorSystem") /*返回ActorSystem的LoggingAdpater*/ val systemLog = system.log /*通过ActorSystem#actorOf创建MyActor指定名称为myactor的顶级Actor*/ val myactor = system.actorOf(Props[MyActor],name="topActor") systemLog.info("准备向Top Actor--MyActor发送消息") /*向myactor发送消息*/ myactor ! "test" myactor ! "123" /*通过ActorSystem#actorOf创建ContextActor,然后在其内部创建一个子的MyActor*/ val contextActor = system.actorOf(Props[ContextActor],name="childActor") systemLog.info("准备向Child Actor--MyActor发送消息") contextActor ! "hadoop" contextActor ! "hive" /*关闭ActorSystem,停止程序的运行*/ system.shutdown()}
得到的结果如下:
准备向TopActor--MyActor发送消息
[akka://MyActorSystem/user/topActor] Received Test
[akka://MyActorSystem/user/topActor] ReceivedUnknown Message
准备向ChildActor--MyActor发送消息
[akka://MyActorSystem/user/childActor/ChildActor]Received Unknown Message
[akka://MyActorSystem/user/childActor] Receivedhadoop
[akka://MyActorSystem/user/childActor] Receivedhive
[akka://MyActorSystem/user/childActor/ChildActor]Received Unknown Message
结论:通过context创建子的Actor这种方式,可以支持链式调用
四 Actor的path
通过以上运行的结论:
akka://MyActorSystem/user/topActor
akka://MyActorSystem/user/childActor/ChildActor
五 Actor API的使用
5.1 hook方法
preStart,postStop方法
import akka.actor._import akka.actor.Actor.Receiveclass HookActor extends Actor with ActorLogging{ var child:ActorRef = _ /*preStart(),Actor启动之前调用,用于完成初始化工作*/ @throws[Exception](classOf[Exception]) override def preStart(): Unit = { log.info("[preStrat method invoked]") child = context.actorOf(Props[MyActor],name="myChild") } def receive: Receive = { case msg => child ! msg;log.info("Received "+msg) } /*postStop(),Actor停止之后调用*/ @throws[Exception](classOf[Exception]) override def postStop(): Unit = { log.info("[postStop method invoked]") context.stop(child) }}object HookActor extends App { val system = ActorSystem("HookActorSystem") val hook = system.actorOf(Props[HookActor],name="hook") hook ! "Welcome You" hook ! "Nice to meet you" system.terminate()}
5.2成员变量self及成员方法sender方法的使用
self ! 消息:指的是自己向自己发送一条消息
sender ! 或者 sender() !消息 指定的是向给自己发送消息的Actor发送一条消息,如果没有给自己发送消息的Actor,则不会投递消息
class MyActor extends Actor{ self ! "MSG FROM MYSELF" //获取LoggingAdapter,用于日志输出 val log = Logging(context.system,this) def receive = { case "test" => log.info("[MyActor]=> test") sender()!"MSG FROM MyActor" case "MSG FROM MYSELF" => log.info("[MyActor]=> MSG FROM MYSELF") case "MSG FROM MyActor" => log.info("[MyActor]=>MSG FROM MyActor") case _ => log.info("[MyActor]=> Unkown Message"); }}object MyActor extends App { /*ActorSystem 用于创建维护Actor*/ val system = ActorSystem("MyActorSystem") /*返回ActorSystem的LoggingAdpater*/ val systemLog = system.log /*通过ActorSystem#actorOf创建MyActor指定名称为myactor的顶级Actor*/// val myactor = system.actorOf(Props[MyActor],name="topActor")// systemLog.info("准备向Top Actor--MyActor发送消息")// /*向myactor发送消息*/// myactor ! "test" /*通过ActorSystem#actorOf创建ContextActor,然后在其内部创建一个子的MyActor*/ val contextActor = system.actorOf(Props[ContextActor],name="childActor") systemLog.info("准备向Child Actor--MyActor发送消息") contextActor ! "test" /*关闭ActorSystem,停止程序的运行*/ system.shutdown()}
class ContextActor extends Actor with ActorLogging{ val childActor = context.actorOf(Props[MyActor], name = "ChildActor") def receive: Receive = { case msg => childActor ! msg; log.info("[ContextActor]=> "+msg) }}
[akka://MyActorSystem/user/childActor][ContextActor]=> test
[akka://MyActorSystem/user/childActor/ChildActor][MyActor]=> MSG FROM MYSELF
[akka://MyActorSystem/user/childActor/ChildActor][MyActor]=> test
[akka://MyActorSystem/user/childActor/ChildActor][MyActor]=>MSG FROM MyActor
[akka://MyActorSystem/user/childActor][ContextActor]=> MSG FROM MyActor
5.3 unhandle方法的使用
unhandled方法用于处理没有被receive方法处理的消息,比如case 中并没有针对没有匹配的消息的处理case _ 语句,在实际开发过程中,可能会对不能被处理的消息增加一些应对逻辑,此时可以重写unhandled方法
class UnhandleActor extends Actor with ActorLogging{ def receive = { case "hello" => println("hello, nice to meet you!") } /*重写unhandled方法*/ override def unhandled(message: Any): Unit = { log.info("UNHANDLED MSG {}",message.toString.toUpperCase()) }}object UnhandleActor { def main(args: Array[String]) { val system = ActorSystem("UnhandleActor") val unhandle = system.actorOf(Props[UnhandleActor],name="unhandle") unhandle ! "hello" unhandle ! "business dias" }}
六 Actor的停止
6.1 通过ActorSystem#shutdown(过时) 或者ActorSystem#terminate
停止所有Actor运行
object UnhandleActor { def main(args: Array[String]) { val system = ActorSystem("UnhandleActor") val unhandle = system.actorOf(Props[UnhandleActor],name="unhandle") unhandle ! "hello" unhandle ! "business dias" //system.shutdown() system.terminate() }}
6.2 通过ActorContext停止某一个Actor
class HookActor extends Actor with ActorLogging{ var child:ActorRef = _ /*preStart(),Actor启动之前调用,用于完成初始化工作*/ @throws[Exception](classOf[Exception]) override def preStart(): Unit = { log.info("[preStrat method invoked]") child = context.actorOf(Props[MyActor],name="myChild") } def receive: Receive = { case "self" => sender() ! "test" case msg => child ! msg;log.info("Received "+msg) } /*postStop(),Actor停止之后调用*/ @throws[Exception](classOf[Exception]) override def postStop(): Unit = { log.info("[postStop method invoked]") context.stop(child) }}
6.3 通过发送消息的形式通知Actor关闭
语法格式 actor ! PoisonPill
class MyActor extends Actor{ //获取LoggingAdapter,用于日志输出 val log = Logging(context.system,this) def receive = { case "test" => log.info("[MyActor]=> test") sender()!"MSG FROM MyActor" case _ => log.info("[MyActor]=> Unkown Message"); } @throws[Exception](classOf[Exception]) override def postStop(): Unit = { log.info("[MyActor][postStop method invoked]") }}
class HookActor extends Actor with ActorLogging{ var child:ActorRef = context.actorOf(Props[MyActor],name="myChild") def receive: Receive = { case "stop" => child ! PoisonPill case msg => child ! msg;log.info("[HookActor]=> "+msg) }}object HookActor extends App { val system = ActorSystem("HookActorSystem") val hook = system.actorOf(Props[HookActor],name="hook") hook ! "Nice to meet you" hook ! "stop"}
七 Actor 消息模型
Akka中,消息可以以2种模型来传递给Actor, 如下:
7.1 Fire and Forget
消息生产者不期望从消费者得到答复,这种消息是异步方式发送,然后立即返回,Akka actors使用tell()方法指示该消息是Fire and Forget模式
import akka.actor.Actor.Receiveimport akka.actor.{ActorSystem, Props, ActorLogging, Actor}case class Animal(msg:String)case class Human(msg:String)case class Plant(msg:String)case class UFO(msg:String)class FireAndForgetActor extends Actor with ActorLogging{ def receive: Receive = { case Animal(msg) => log.info("[Animal] => {}", msg) case Human(msg) => log.info("[Human] => {}", msg) case Plant(msg) => log.info("[Plant] => {}", msg) case _ => log.info("Hahah") }}class SendActor extends Actor with ActorLogging{ val child = context.actorOf(Props[FireAndForgetActor],name="tell") def receive: Receive = { case msg => child.tell(msg,sender) } override def unhandled(message: Any): Unit = { log.info("[Unhandled Message] => {}",message) }}object SendActor extends App { val system = ActorSystem("SendActorSystem") val send = system.actorOf(Props[SendActor],name="send") val animal = new Animal("我是老虎") val human = new Human("我是隔壁那啥") val plant = new Plant("我是小草") val ufo = new UFO("我是来自xxx星球的") send ! animal send ! human send ! plant send ! ufo system.terminate()}
7.2 Send and Receive
这种模式,生产者期望从消费者得到一个答复,而且需要等这个答复,这种模式也是异步发送的,返回一个Future, kka actors 使用ask()方法发送消息然后等待答复的future
import java.util.concurrent.TimeUnitimport scala.concurrent.ExecutionContext.Implicits.globalimport akka.actor.Actor.Receiveimport akka.actor._import akka.pattern.askimport akka.pattern.pipeimport akka.util.Timeoutimport scala.concurrent.Futurecase class Animal(msg:String)case class Human(msg:String)case class Plant(msg:String)case class UFO(msg:String)class FireAndForgetActor extends Actor with ActorLogging{ def receive: Receive = { case Animal(msg) => log.info("[Animal] => {}", msg) case Human(msg) => log.info("[Human] => {}", msg) case Plant(msg) => log.info("[Plant] => {}", msg) case _ => log.info("Hahah") }}class SendAndReceiveActor extends Actor with ActorLogging{ def receive: Receive = { case "动物" => sender ! new Animal("老虎") case "人类" => sender ! new Human("小明") case "植物" => sender ! new Plant("杜鹃花") case _ => sender ! new UFO("UFO") }}class RunActor extends Actor with ActorLogging{ implicit val timeout = Timeout(5,TimeUnit.MILLISECONDS) val askActor = context.actorOf(Props[SendAndReceiveActor],name="ask") val tellActor = context.actorOf(Props[FireAndForgetActor],name="tell") def receive: Receive = { case "动物" => val result:Future[Animal] = for { obj <- ask(askActor,"动物").mapTo[Animal] } yield obj pipe(result).to(tellActor) case "人类" => val result:Future[Human] = for { obj <- ask(askActor,"人类").mapTo[Human] } yield obj pipe(result).to(tellActor) case "植物" => val result:Future[Plant] = for { obj <- ask(askActor,"植物").mapTo[Plant] } yield obj pipe(result).to(tellActor) case "不明飞行物" => val result:Future[UFO] = for { obj <- ask(askActor,"不明飞行物").mapTo[UFO] } yield obj pipe(result).to(tellActor) }}class SendActor extends Actor with ActorLogging{ val child = context.actorOf(Props[FireAndForgetActor],name="tell") def receive: Receive = { case msg => child.tell(msg,sender) } override def unhandled(message: Any): Unit = { log.info("[Unhandled Message] => {}",message) }}object SendActor extends App { val system = ActorSystem("SendActorSystem") val send = system.actorOf(Props[RunActor],name="send") send ! "动物" send ! "人类" send ! "植物" send ! "不明飞行物" Thread.sleep(2000) system.terminate()}
注意点:
必须声明一个隐式timeout参数:
implicit val timeout = Timeout(5,TimeUnit.
MILLISECONDS)
必须引入import scala.concurrent.ExecutionContext.
Implicits.global
ask 方法不是Actor自己,需要引入import akka.pattern.ask
pipe也不是Actor自己的也需要引入:import
akka.pattern.pipe
八 Typed Actor
8.1 什么是Typed Actor
Typed Actor是Active Objects设计模式的实现. Active Objects模式将方法的执行和方法的调用进行解耦合,从而为程序引入并发性。Typed Actor由公用的接口和对应实现两部分构成
我们来看看Active Object模式是怎么实现解耦的:
# 客户端调用代理对象的方法
# 代理对象不断传递方法调用作为Method Request到一个调度器或者Invocation Handler去拦截这些请求
# 调度器Scheduler或者InvocationHandler将Method Request放入队列
# 调度器连续不断的监控队列,然后决定哪一个Method Request是可以运行的,如果被调用了,则从队列中移除
# Scheduler或者Invocation Handler分发Method Request 到 这个方法实现类(implementationobject)
# 这个实现类和运行Scheduler处于相同的线程,处理请求然后与返回客户端Future
8.2 创建Type Actor,并发送消息
第一步: 先定义接口或者特质
traitCalculatorInt {
def add(first:Int,second:Int):Future[Int]
def subtract(first:Int,second:Int):Future[Int]
def incrementCount():Unit
}
第二步:继承Trait,并实现方法
importscala.concurrent.{Promise, Future}
import akka.actor.TypedActor.dispatcher
/**
* Future:表示一个可能还没有实际完成的异步任务的结果
* 为了使Future完全非阻塞,注册Callback到Future中,一旦future完成,Callback会被异步执行
* Promise:是一个可写的,只能赋一次值的容器,Promise存储计算结果,从Promise中可以得到Future,
* 由Promise来完成Future. 也可以从字面上来理解,Promise也就是一个承诺,就好比去买一杯咖啡,
* 付账过后,服务员承诺会给你一杯咖啡,但需要过几分钟才能领取这杯咖啡.服务员制作咖啡的过程就是
* 一个Future,而付账过后,就得到服务员的一个Promise。
*/
class Calculatorextends CalculatorInt{
var counter = 0;
def add(first: Int,second: Int): Future[Int] = {
Promise.successful[Int](first+ second).future
}
def subtract(first: Int,second: Int): Future[Int] = {
Promise.successful[Int](first- second).future
}
def incrementCount(): Unit = {
counter += 1
Some(counter)
}
}
第三步 创建TypeActor
# 方式一:直接通过默认的构造函数创建Typed Actor
val_system = ActorSystem("TypedActorsExample")
val c:CalculatorInt= TypedActor(_system).typedActorOf(TypedProps[Calculator]())
# 方式二:直接通过默认的构造函数创建Typed Actor并指定Typed Actor名称
val c1:CalculatorInt= TypedActor(_system).typedActorOf(TypedProps[Calculator](),"myCalculator")
方式三:通过非默认的构造函数创建Typed Actor并指定Typed Actor名称
val c2:CalculatorInt= TypedActor(_system).typedActorOf(TypedProps(classOf[CalculatorInt],newCalculator), "myCalculator")
第四步 : 发送消息
第一种:Fire and Forget
c.incrementCount()
第二种:Send and Receive
val future = c.add(14,6)val durations = Duration.apply(5,TimeUnit.SECONDS);val result = Await.result(future,durations)
8.3 停止Type Actor
有两种方式停止Type Actor:
TypedActor(_system).stop(c)TypedActor(_system).poisonPill(c)
8.4 Type Actor 声明周期监控
通过实现TypeActor.PreStart和TypeActor.PostStop接口,在actor开始和结束的时候,我们可以添加一些功能
class Calculator extends CalculatorInt with PreStart with PostStop{ var counter = 0; override def preStart(): Unit = { println("[preStart] method invoked") } def add(first: Int, second: Int): Future[Int] = { Promise.successful[Int](first + second).future } def subtract(first: Int, second: Int): Future[Int] = { Promise.successful[Int](first - second).future } def incrementCount(): Unit = { counter += 1 Some(counter) } override def postStop(): Unit = { println("[postStop] method invoked") }}
- Akka之actor模型
- akka---actor模型
- 【Akka】Actor模型探索
- scala之Akka的Actor模型(下)
- scala之Akka的Actor模型(上)
- Akka笔记之Actor简介
- Actor编程模型——akka
- Actor模型和Akka消息驱动系统
- 对于akka中,actor模型的理解。
- Akka actor
- Akka并发编程——1、Actor模型(一)
- Akka并发编程——2、Actor模型(二)
- Akka并发编程——3、Actor模型(三)
- Akka并发编程——4、Actor模型(四)
- Akka并发编程——5、Actor模型(五)
- .NET的Actor模型:Orleans Orleans是微软推出的类似Scala Akka的Actor模型,
- Akka Actor 模型云计算架构以及 Remote Actor的简单示例
- Akka并发编程——第五节:Actor模型(四) 停止Actor
- 在centos安装mysql的rpm模式
- Android 7.0自动安装APP并启动
- LLVM每日谈之二十五 Clangd和LSP
- 大小写转换
- hibernate学习教程-封装分页查询
- Akka之actor模型
- Python错误 SyntaxWarning: name 'xxx' is assigned to before global declaration
- 业界 | Poseidon:高效的分布式深度学习通信架构
- Docker之创建并进入mysql容器
- java基础之持有对象
- 人工智能之搜索方法
- spring cloud + spring boot + springmvc+mybatis分布式微服务云架构
- mt2503 [MAKE]加入BT switch机制后,makefile文件的变化
- windows平台使用Microsoft Visual C++ Compiler for Python 2.7编译python扩展