设为首页 加入收藏

TOP

Akka(7): FSM:通过状态变化来转换运算行为(一)
2017-10-09 14:06:32 】 浏览:4130
Tags:Akka FSM 通过 状态 变化 转换 运算 行为

  在上篇讨论里我们提到了become/unbecome。由于它们本质上是堆栈操作,所以只能在较少的状态切换下才能保证堆栈操作的协调及维持程序的清晰逻辑。对于比较复杂的程序流程,Akka提供了FSM:一种通过状态变化进行功能切换的Actor。FSM模式的状态转变特别适合对应现实情况中的程序流程,我们可以用每一种状态来代表一个程序流程。FSM是个trait,定义如下:

trait FSM[S, D] extends Actor with Listeners with ActorLogging {...}

我们看到:FSM就是一个特殊的Actor。带着两个类型参数:S代表状态类型,D代表状态数据类型。实际上S和D结合起来就是FSM的内部状态,即:SomeState+DataX 和 SomeState+DataY分别代表不同的Actor内部状态,这点从State定义可以得到信息:

/** * This captures all of the managed state of the [[akka.actor.FSM]]: the state * name, the state data, possibly custom timeout, stop reason and replies * accumulated while processing the last message. */
  case class State[S, D](stateName: S, stateData: D, timeout: Option[FiniteDuration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) {...}

我们可以用下面的表达式来代表FSM功能:

State(SA) x Event(E) -> Actions (A), State(SB)

意思是:假如在状态SA发生了事件E,那么FSM应该实施操作A并把状态转换到SB。这里面操作Action代表某项功能,事件Event是个新的类型,定义如下:

/** * All messages sent to the [[akka.actor.FSM]] will be wrapped inside an * `Event`, which allows pattern matching to extract both state and data. */ final case class Event[D](event: Any, stateData: D) extends NoSerializationVerificationNeeded

Event[D]是个包嵌消息和数据的类型。理论上FSM是通过接收Event来确定运行功能和下一个状态转换,就像普通的Actor接收Message原理一样。我们用上一篇里的FillSeasons作为这次FSM示范的例子。首先定义State,Data: 

trait Seasons   //States
case object Spring extends Seasons case object Summer extends Seasons case object Fall extends Seasons case object Winter extends Seasons class SeasonInfo(talks: Int, month: Int)  //Data
case object BeginSeason extends SeasonInfo(0,1)

四个状态分别是:春夏秋冬。SeasonInfo代表数据类型,含被问候次数talks,季中月份month两个参数,每季含1,2,3三个月份。目前我们只支持两种功能消息:

object FillSeasons { sealed trait Messages    //功能消息
  case object HowYouFeel extends Messages case object NextMonth extends Messages }

这种普通Actor的消息类型对应到FSM的Event类型中的event:Any。也就是说FSM在收到功能消息后需要构建一个Event类型实例并把消息包嵌在里面。因为FSM继承了Actor,所以它必须实现receive函数。下面是FSM.receive的源代码:

 /* * ******************************************* * Main actor receive() method * ******************************************* */
  override def receive: Receive = { case TimeoutMarker(gen) ? if (generation == gen) { processMsg(StateTimeout, "state timeout") } case t @ Timer(name, msg, repeat, gen) ? if ((timers contains name) && (timers(name).generation == gen)) { if (timeoutFuture.isDefined) { timeoutFuture.get.cancel() timeoutFuture = None } generation += 1
        if (!repeat) { timers -= name } processMsg(msg, t) } case SubscribeTransitionCallBack(actorRef) ? // TODO Use context.watch(actor) and receive Terminated(actor) to clean up list
 listeners.add(actorRef) // send current state back as reference point
      actorRef ! CurrentState(self, currentState.stateName) case Listen(actorRef) ? // TODO Use context.watch(actor) and receive Terminated(actor) to clean up list
 listeners.add(actorRef) // send current state back as reference point
      actorRef ! CurrentState(self, currentState.stateName) case UnsubscribeTransitionCallBack(actorRef) ? listeners.remove(actorRef) case Deafen(actorRef) ? listeners.remove(actorRef) case value ? { if (timeoutFuture.isDefined) { timeoutFuture.get.cancel() timeoutFuture = None } generation += 1 processMsg(value, sender()) }

除timer,subscription等特殊功能外,case value => ... 就是处理自定义消息的地方了。我们看到FSM是用processMsg(value, sender())来处理消息的。processMs

首页 上一页 1 2 3 4 5 6 下一页 尾页 1/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Akka(6): become/unbecome:运.. 下一篇spark获取时间

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目