How to write a timer actor in Scala?

后端 未结 6 881
忘了有多久
忘了有多久 2020-12-20 12:30

I need an actor to send a message every minute. How do I best achieve this behaviour? I am afraid of using java.lang.Thread.sleep(long millis) as a thread can b

相关标签:
6条回答
  • 2020-12-20 13:10

    You can use Akka FSM to model an actor that stays forMax millis in a waiting state and then sends a message, e.g. by switching to another state while using onTransition and staying there for 0 millis to switch back to waiting state. There is a good example at the akka page.

    0 讨论(0)
  • 2020-12-20 13:16
    import scala.actors._
    class Wakeup[A](millis: Int, who: ReplyReactor, alarm: A) extends Thread {
      val done = new java.util.concurrent.atomic.AtomicBoolean(false)
      override def run {
        while (!done.get()) {
          who ! alarm
          Thread.sleep(millis)
        }
      }
    }
    case object BEEP {}
    val a = new ReplyReactor { def act { loop { react {
      case BEEP => println("Wha?!  "+new java.util.Date)
      case _ =>
    }}}}
    val b = new Wakeup(60000,a,BEEP)
    a.start
    

    Why use an actor when a thread is what you want?

    scala> b.start
    
    scala> Wha?!  Mon Nov 07 18:43:18 EST 2011
    Wha?!  Mon Nov 07 18:44:18 EST 2011
    Wha?!  Mon Nov 07 18:45:18 EST 2011
    Wha?!  Mon Nov 07 18:46:18 EST 2011
    Wha?!  Mon Nov 07 18:47:18 EST 2011
    Wha?!  Mon Nov 07 18:48:18 EST 2011
    Wha?!  Mon Nov 07 18:49:18 EST 2011
    Wha?!  Mon Nov 07 18:50:18 EST 2011
    Wha?!  Mon Nov 07 18:51:18 EST 2011
    Wha?!  Mon Nov 07 18:52:18 EST 2011
    
    0 讨论(0)
  • 2020-12-20 13:21

    Or as @Daniel mentioned, here a running example:

    import scala.actors._
    import scala.actors.Actor._
    
    class TimerActor(val timeout: Long,val who: Actor,val reply: Any) extends Actor {
      def act {
        loop {
          reactWithin(timeout) {
            case TIMEOUT => who ! reply
          }
        }
      }
    }
    
    val a = actor {
      loop {
        react {
          case x => println(x)
        }
      }
    }
    
    val t = new TimerActor(1000, a, "Go for it")
    
    a.start
    t.start
    
    0 讨论(0)
  • 2020-12-20 13:24

    Create an actor with receiveWithin to act as the timer.

    0 讨论(0)
  • 2020-12-20 13:33

    I ended up in creation of dedicated Runnable instance, which keeps sending a message to the target actor. Like

    case class QueueTick()
    
    class QueueWatcherActor extends Actor {
    
      override def receive = {
        case QueueTick() => // do it here
      }
    
    }
    
    val ref = ActorSystem("xxx")
    
    val actor = ref.actorOf(Props[QueueWatcherActor])
    
    val executor = Executors.newSingleThreadScheduledExecutor()
    
    executor.scheduleAtFixedRate(new Runnable {
      def run() {
        actor ! QueueTick()
      }
    },1,60,TimeUnit.SECONDS)
    
    0 讨论(0)
  • 2020-12-20 13:33

    Since scala.actors is now deprecated and being replaced with akka actors (and since there is no react or receiveWithin in akka actors), here is how to do it using akka actors (it's actually less of a 'hack' than using receiveWithin anyways IMHO).

    The example below schedule a runnable to be invoked after 5 seconds:

    import akka.actor.{ActorSystem, Scheduler}
    import scala.concurrent.duration.FiniteDuration
    import scala.concurrent.ExecutionContext.Implicits.global
    
    class TimerExample {
    def example() = {
    
        def scheduler: Scheduler = ActorSystem.create("timer-example").scheduler
    
        val myRunnable = new Runnable {
          override def run(): Unit = {
            println("run invoked")
          }
        }
    
        println("scheduling...")
        scheduler.scheduleOnce(FiniteDuration(5,TimeUnit.SECONDS),myRunnable)
        Thread.sleep(6000)
        println("should have printed 'run invoked'")
    }
    
    0 讨论(0)
提交回复
热议问题