问一个演员,当他到达Akka 2的特定州时让他回应

时间:2013-10-15 13:48:04

标签: scala akka actor

我对Akka很陌生,所以我的问题看似简单:

我有一个名为workerA的演员使用FSM,因此可以处于这两个状态FinishedComputing

sealed trait State
case object Finished extends State
case object Computing extends State

sealed trait Data
case object Uninitialized extends Data
case class Todo(target: ActorRef, queue: immutable.Seq[Any]) extends Data

workerA收到GetResponse时,如果只有状态为Finished,它应该回答。

这样做的正确方法是什么?我知道我们应该避免在这个范例中阻止,但在这里它只是关注的顶级演员。 感谢

2 个答案:

答案 0 :(得分:1)

我不一定确定你甚至需要FSM。 FSM是一个非常好的工具,当你有许多状态和这些状态之间的许多可能的(并且可能是复杂的)状态转换时。在你的情况下,如果我理解正确,你基本上有两种状态;收集数据并完成。似乎只有一个状态转换,从gathering -> finished开始。如果我这一切都正确,那么我建议你只需使用become来解决问题。

我在下面有一些代码来展示我所描述的一个简单的例子。基本的想法是,主要的演员将一些工作交给一些工人,然后等待结果。如果有人在工作完成时询问结果,那么演员会将该请求存储起来,直到工作完成为止。完成后,演员将回复任何要求结果的人。代码如下:

case object GetResults
case class Results(ints:List[Int])
case object DoWork

class MainActor extends Actor with Stash{
  import context._

  override def preStart = {
    val a = actorOf(Props[WorkerA], "worker-a")
    val b = actorOf(Props[WorkerB], "worker-b")
    a ! DoWork
    b ! DoWork
  }

  def receive = gathering(Nil, 2)

  def gathering(ints:List[Int], count:Int):Receive = {
    case GetResults => stash()
    case Results(i) =>      
      val results = i ::: ints
      val newCount = count - 1
      if (newCount == 0){
        unstashAll()
        become(finished(results))        
        child("worker-a") foreach (stop(_))
        child("worker-b") foreach (stop(_))
      }
      else
        become(gathering(results, newCount))
  } 

  def finished(results:List[Int]):Receive = {
    case GetResults => sender ! results
  }
}

class WorkerA extends Actor{
  def receive = {
    case DoWork =>

      //Only sleeping to simulate work.  Not a good idea in real code
      Thread sleep 3000
      val ints = for(i <- 2 until 100 by 2) yield i
      sender ! Results(ints.toList)
  }
}

class WorkerB extends Actor{
  def receive = {
    case DoWork =>

      //Only sleeping to simulate work.  Not a good idea in real code
      Thread sleep 2000  
      val ints = for(i <- 1 until 100 by 2) yield i
      sender ! Results(ints.toList)      
  }
}

然后你可以按如下方式测试它:

val mainActor = system.actorOf(Props[MainActor])
val fut = mainActor ? GetResults
fut onComplete (println(_))

答案 1 :(得分:0)

您可以在FSM状态上进行模式匹配:

// insert pattern matching stuff instead of ...

class MyActor extends Actor with FSM[State, Message] {
  startWith(Finished, WaitMessage(null))

  when(Finished) {
    case Event(Todo(... =>
      // work
      goto(Computing) using Todo(...)
    case Event(GetResponse(... =>
      // reply: sender ! msg // or similar
  }

  /* the rest is optional. You can use onTransition below to send yourself a message to    report status of the job: */
  when(Busy) {
    case Event(Finished(... =>
      // reply to someone: sender ! msg // or similar
      goto(Finished)
  }

  onTransition {
    case Finished -> Computing =>
      // I prefer to run stuff here in a future, and then send a message to myself to signal the end of the job:
      self ! Finished(data)
  }

编辑以更具体地解决问题:

class MyActor extends Actor with FSM[State, Message] {
  startWith(Finished, WaitMessage(null))

  when(Finished) {
    case Event(Todo(... =>
      // work
      goto(Computing) using Todo(...)
    case Event(GetResponse(... =>
      // reply: sender ! msg // or similar
      stay
  }

  initialize()
}