我对Akka很陌生,所以我的问题看似简单:
我有一个名为workerA
的演员使用FSM,因此可以处于这两个状态Finished
和Computing
:
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
,它应该回答。
这样做的正确方法是什么?我知道我们应该避免在这个范例中阻止,但在这里它只是关注的顶级演员。 感谢
答案 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()
}