快学Actor编程

2022-05-17 14:52:47 浏览数 (3)

代码语言:javascript复制
package actor
 
import akka.actor.{Actor, ActorSystem, Props}
 
 
/**
 * 当继承actor后,就是一个Actor,核心方法receive 方法重写
 */
class SayHelloActor extends Actor {
  /**
   * 1. receive 方法,会被Actor的mailbox(实现了Runnable接口)调用
   * 2.当该Actor的mailbox 接收到消息,就会调用了receive
   * 3.type receive = PartialFunction[Any,Unit]
   *
   * @return
   */
  override def receive: Receive = {
    case "hello" => println("收到hello,回应hello too :)")
    case "ok" => println("收到ok,回应ok too :)")
    case "exit" => {
      println("接收到exit,退出系统")
      context.stop(self) //停止actorref
      context.system.terminate() // 退出actorsystem
    }
    case _ => println("匹配不到")
  }
}
 
object SayHelloActor {
  //1.先创建一个ActorSystem,专门用于创建Actor
  val actorFactory = ActorSystem("actorFactory")
  //2.创建一个Actor的同时,返回Actor的ActorRef
  //Props[SayHelloActor] c创建了一个sayhelloActor实例,使用反射
  //“sayhelloactor" 给actor取名
  //sayHelloActorRef :Actor就是Props[SayHelloActor] 的ActorRef
  //创建的sayhelloRef 被ActorSystem接管
  val sayHelloActorRef = actorFactory.actorOf(Props[SayHelloActor], "sayHelloActor")
 
  def main(args: Array[String]): Unit = {
    //给SayHelloActor 发消息(邮箱)
    sayHelloActorRef ! "hello"
    sayHelloActorRef ! "ok"
    sayHelloActorRef ! "exit"
  }
}

简单来说,Actor通过消息传递的方式与外界通信,而且消息传递是异步的。每个Actor都有一个邮箱,邮箱接收并缓存其他Actor发过来的消息,通过邮箱队列mail queue来处理消息。Actor一次只能同步处理一个消息,处理消息过程中,除了可以接收消息外不能做任何其他操作。

每个Actor是完全独立的,可以同时执行他们的操作。每个Actor是一个计算实体,映射接收到的消息并执行以下动作:发送有限个消息给其他Actor、创建有限个新的Actor、为下一个接收的消息指定行为。这三个动作没有固定的顺序,可以并发地执行,Actor会根据接收到的消息进行不同的处理。

在Actor系统中包含一个未处理的任务集,每个任务都由三个属性标识:

  • tag用以区分系统中的其他任务
  • target 通信到达的地址
  • communication 包含在target目标地址上的Actor,处理任务时可获取的信息。

为简单起见,可见一个任务视为一个消息,在Actor之间传递包含以上三个属性的值的消息。

Actor模型有两种任务调度方式:基于线程的调度、基于事件的调度

  • 基于线程的调度 为每个Actor分配一个线程,在接收一个消息时,如果当前Actor的邮箱为空则会阻塞当前线程。基于线程的调度实现较为简单,但线程数量受到操作的限制,现在的Actor模型一般不采用这种方式。
  • 基于事件的调度 事件可以理解为任务或消息的到来,而此时才会为Actor的任务分配线程并执行。

因此,可以把系统中所有事物都抽象成为一个Actor:

  • Actor的输入是接收到的消息
  • Actor接收到消息后处理消息中定义的任务
  • Actor处理完成任务后可以发送消息给其它Actor

在一个系统中可以将一个大规模的任务分解为一些小任务,这些小任务可以由多个Actor并发处理,从而减少任务的完成时间。

Actor模型本身确保处理是按照同步的方式执行的。TicketsActor会处理其收件箱中的每条消息,注意这里没有复杂的线程或锁,只是一个多线程的处理过程,但Actor系统会管理线程的使用和分配。

Actor是由状态(state)、行为(behavior)、邮箱(mailbox)三者组成的。

  • 状态(state):状态是指actor对象的变量信息,状态由actor自身管理,避免并发环境下的锁和内存原子性等问题。
  • 行为(behavior):行为指定的是actor中计算逻辑,通过actor接收到的消息来改变actor的状态。
  • 邮箱(mailbox):邮箱是actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送发消息,而接收方则从邮箱中获取消息。

Actor模型描述了一组为避免并发编程的公理:

  • 所有的Actor状态是本地的,外部是无法访问的。
  • Actor必须通过消息传递进行通信
  • 一个Actor可以响应消息、退出新Actor、改变内部状态、将消息发送到一个或多个Actor。
  • Actor可能会堵塞自己但Actor不应该堵塞自己运行的线程

0 人点赞