How to write a timer actor in Scala?

淺唱寂寞╮ 提交于 2019-12-18 07:36:46

问题


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 be shared among many actors in Scala, as far as I understand.


回答1:


Create an actor with receiveWithin to act as the timer.




回答2:


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



回答3:


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.




回答4:


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



回答5:


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)



回答6:


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'")
}


来源:https://stackoverflow.com/questions/8043815/how-to-write-a-timer-actor-in-scala

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!