让演员入睡

アレッ*_*ックス 2 multithreading scala actor akka

我想打一个演员睡一会儿,具体地说,它应该决定是否要睡觉本身取决于条件:

class MyActor extends Actor {
  def receive {
    case "doWork" => doWork()
  }

  def doWork(): Unit = {
    // doing some work
    val condition = calculateCondition
    if (condition) {
      // sleep for 5 seconds
      // Thread.sleep(5000) 
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我非常确定Thread.sleep(5000) 在演员内部打电话并不是一件好事,应该有另一种方式.因此,我该如何让它睡觉?

Sha*_*nds 8

I would look to do this using changes of state/behaviour for the Actor. Akka gives you a couple of means of doing this: you can implement a full-on state machine, or make use of context.become (and mix in akka.actor.Stash), and have the actor pass (scheduled) messages to itself. The former feels like overkill for this case, so here is how I would look to code it up:

import akka.actor._    
import scala.concurrent.duration._

class MySleepyActor(duration: FiniteDuration = (5 seconds)) extends Actor with Stash {

  import context._

  override def preStart() { become(running) }

  def receive = PartialFunction.empty

  def running: Actor.Receive = {
    case "doWork" =>       
      if (doWork()) {
        scheduleReactivate
        become(paused)
      }
    case "wakeUp" => // already awake
  }

  def paused: Actor.Receive = {
    case "doWork" => stash()
    case "wakeUp" => 
      unstashAll()
      become(running)
  }

  def scheduleReactivate: Unit = {
    system.scheduler.scheduleOnce(duration, self, "wakeUp")
  }

  def doWork(): Boolean = {
    // doing some work, then:
    calculateCondition
  }
}
Run Code Online (Sandbox Code Playgroud)

Note: I have not tested this code! Should give you some ideas to work with, though.