Akka Actor模型的简介与Actor的创建方式
【摘要】 Akka Actor其具有以下特点:
系统中的所有事物都可以扮演一个ActorActor之间完全独立在收到消息时,Actor所采取的所有动作都是并行的,在一个方法中的动作没有明确的顺序Actor有标识和当前行为描述Actor可能被分成原始和非原始类别非原始Actor有一个由邮件地址表示的标识当前行为由一组知识(实例变量或本地状态)和定义Actor在收到消息时将采取的动...
Akka Actor其具有以下特点:
- 系统中的所有事物都可以扮演一个Actor
- Actor之间完全独立
- 在收到消息时,Actor所采取的所有动作都是并行的,在一个方法中的动作没有明确的顺序
- Actor有标识和当前行为描述
- Actor可能被分成原始和非原始类别
- 非原始Actor有一个由邮件地址表示的标识
- 当前行为由一组知识(实例变量或本地状态)和定义Actor在收到消息时将采取的动作组成
- 消息传递是非阻塞和异步的,其机制是邮件队列
- 所有消息发送都是并行的。
绝大多数流行语言的并发是基于多线程之间的共享内存,使用同步方法防止写争夺,但Akka提供的则是基于Actor的并发模型。
Akka将复杂的Actor通信、Actor注册、Actor查找进行了封装。用户在写自己的Actor时,只需要实现akka.actor.Actor这个接口。
在Akka框架中,每一个Actor都有一个唯一的URL,该URL的定义格式和万维网地址的定义格式非常相似。
每一个Actor通过ActorSystem和Context初始化的时候,都会得到自己唯一的路径,路径格式如:akka.tcp://systemName@ip:port/user/topActorName/otherActorName,并且可以通过actorSelection(path)方法查找对应路径的Actor对象,该方法返回该Actor的引用。得到Actor后就可以发送消息了。
创建Actor
(1)通过实现akka.actor.Actor来创建Actor类
要定义自己的Actor类,需要继承Actor并实现receive方法。receive方法需要定义一系列case语句,来描述Actor能够处理哪些消息(使用标准的Scala模式匹配),以及实现对消息如何进行处理的代码。
import akka.actor._
object HelloScala {
def main(args: Array[String]): Unit = { val _system = ActorSystem("HelloScalaNo7") // Props[MyActor]这里一定要写对 val myActor = _system.actorOf(Props[MyActor],"iLoveMyActor") myActor ! "Hello My love"
}
}
class MyActor extends Actor{
override def receive: Receive = { case str: String => println(str) case _ =>
}
}
Akka Actor receive消息循环是“无穷无尽的”。在receive方法中,提供一个对它能够接受消息的匹配规则,如果希望处理未知的消息,可以像上述代码中一样提供一个缺省的case分支,否则会有akka.actor.UnhandledMessage(message,sender,recipient)被发布到Actor系统(ActorSystem)的事件(EventStream)中。
上述代码中的actorOf的调用将返回一个实例的引用,这个引用是Actor访问句柄,可以用它来与实际的Actor进行交互。
ActorRef是不可变量,与它所代表的Actor之间是一对一的关系。ActorRef是可序列化的,并且它携带了网络信息。这意味着可以将它序列化以后,通过网络进行传送,在远程主机上它仍然代表原结点上的同一个Actor。
上述代码中,Actor是从系统创建的。也可以在其他的Actor中,使用Actor上下文(context)来创建,其中的区别在于监管树的组织方式。使用上下文时当前Actor将成为其创建子Actor的监管者。而使用系统创建的Actor将成为顶级Actor,它由系统(内部监管Actor)来监管。
(2)使用Actor的context创建Actor:
import akka.actor._
object HelloScala { def main(args: Array[String]): Unit = { val _system = ActorSystem("HelloScala") // firstActor是使用系统创建的Actor,它将成为顶级Actor,它由系统(内部监管Actor)来监管。 val firstActor = _system.actorOf(Props[FirstActor],"firstActor") firstActor ! "Hello MyActor!How are you?"
}
}
class MyActor extends Actor{
override def receive: Receive = { case str: String => println(s"test actor receive # ${str}") case _ =>
}
}
class FirstActor extends Actor{
// context 方法创建Actor,使用上下文时当前Actor将成为其创建子Actor的监管者,所以FirstActor成为MyActor的监管者
val myActor = context.actorOf(Props[MyActor],"myActor") // 输出监管目录
println(s"MyActor's monitor#${myActor.path.parent.getElements.toString}") // Actor启动,preStart方法自动调用
override def preStart(): Unit = println("FirstActor's preStart method was called!") override def receive: Receive = { case msg => myActor ! msg // 发给MyActor case _ =>
}
}
(3)使用非缺省构造方法创建Actor
如果Actor的构造方法带参数,那么就不能使用actorOf(Props[TYPE])来创建。可以使用actorOf的非缺省构造方法,这样就可以用任意方式来创建Actor了。
import akka.actor._
object HelloScala { def main(args: Array[String]): Unit = { // 创建名为HelloAkka的ActorSystem val _system = ActorSystem("HelloAkka") // 非缺省构造方法创建,在Props中new 一个Test,并传入参数goat val testActor = _system.actorOf(Props(new Test("goat")),"testActor") testActor ! "Look at the stars!"
}
}
class Test(name: String) extends Actor{
// Actor启动,自动调用preStart方法
override def preStart(): Unit = println("Test Actor preStart method was called!")
override def receive: Receive = { // 匹配打印消息 case str: String => println(s"actor's name:${name}#testActor receive msg:${str}") // 缺省处理 case _ =>
}
}
(4)创建匿名Actor
从某个Actor中派生新的Actor来完成特定的子任务时,可能使用匿名类来包含将要执行的代码会更方便。
import akka.actor._
object HelloScala { def main(args: Array[String]): Unit = { // 创建名为HelloAkka的ActorSystem val _system = ActorSystem("HelloAkka") // 使用ActorSystem的actorOf工厂方法创建Test4 Actor val test4Actor = _system.actorOf(Props[Test4],"test4Actor") test4Actor ! "Look at the stars!HO HO HO "
}
}
class Test4 extends Actor{
// Actor启动,自动调用preStart方法
override def preStart(): Unit = println("Test4 Actor preStart method was called!")
override def receive: Receive = { // 匹配打印消息 case str: String => // 使用context的actorOf方法创建Actor context.actorOf(Props(new Actor { // 创建匿名Actor override def receive: Receive = { case msg: String => println(s"anonymous Actor receive message#${msg}") context.stop(self) // 停止匿名Actor } })).forward(str)// forward会把消息转发给刚刚定义的匿名Actor // 缺省处理 case _ =>
}
}
采用匿名Actor的方式,需要小心地避免捕捉外层Actor的引用,不要在匿名的Actor类中调用外层Actor的方法,这样会破坏Actor的封装,可能会引入同步bug和资源竞争,因为其他的Actor可能会与外层Actor同时进行调度。
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/93177065
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)