33

I have a cache I want to periodically check and prune. In Java, I'd do the following:

new Thread(new Runnable() {
  void run() {
    while (true) { 
      Thread.sleep(1000);
      // clear the cache's old entries
    }
  }
}).start();

Sure, I'd have some issues with thread-safe types to use as the cache, but putting that aside, my question is simple. What's the Scala way of running a recurring background task -- something you don't want running in the application's main thread?

I've used actors a bit and I guess my problem in this scenario is that I don't have anything to generate a message that it's time to clear the cache. Or rather, the only way I can imagine to generate those messages is to create a thread to do it...

EDIT: I need people to vote on answers -- they all look good to me

Jeb
  • 15,939
  • 6
  • 34
  • 37
  • 3
    Thread spawning greatly depends on your system. It maybe to costly for you to have a thread for each such case. Take a look at ScheduledThreadPoolExecutor, you can used it from Scala with some helpers defined in scala.concurrent package – tuxSlayer Jun 14 '11 at 13:31

6 Answers6

26

There are many ways to do that, but I would do something simple like the following.

import scala.concurrent.ops._

spawn {
  while (true) { 
    Thread.sleep(1000);
    // clear the cache's old entries
  }
}

Hope this helps.

k4200
  • 431
  • 6
  • 5
11

You could use Akka Scheduler, which allows you to send a reccuring message to an (akka) actor doing the job. From the doc, just use:

import akka.actor.Scheduler

//Sends messageToBeSent to receiverActor after initialDelayBeforeSending and then after each delayBetweenMessages
Scheduler.schedule(receiverActor, messageToBeSent, initialDelayBeforeSending, delayBetweenMessages, timeUnit)
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • 2
    I think that is code for early versions of Akka; to do the same thing with more recent versions, see http://doc.akka.io/docs/akka/current/java/scheduler.html – Jon Onstott Jan 20 '14 at 06:31
7

Futures is a simple way to do it without explicitly starting a new thread

import scala.actors.Futures._

// main thread code here

future {
   // second thread code here
}

// main thread code here
Jus12
  • 17,824
  • 28
  • 99
  • 157
  • 14
    Futures are designed for _one time_ tasks not _recurring_ tasks. The overhead is significant and unnecessary for a recurring task. – Rex Kerr Jun 14 '11 at 13:35
  • He clearly stated 'recurring'. There's nothing on recurring in your sample. Sorry, -1 – akauppi Mar 28 '13 at 13:33
  • 4
    @RexKerr: But the deprecation information regarding the accepted answer based on `spawn` gives the direction to replace `spawn` by a future. So what is the correct answer for Scala 2.10? @Jus12: To make this work one may have to `import scala.concurrent.ExecutionContext.Implicits.global`. @akauppi: I would accept a `while (true) { ... }` in the future to somehow fulfill recurring... – bluenote10 Mar 12 '14 at 16:05
  • @bluenote10 - I don't see any advantage of using a future over creating a new thread as in Java. If you don't want to use Akka or deprecated methods, just do it the old-fashioned way. – Rex Kerr Mar 12 '14 at 16:15
  • 1
    @RexKerr: I was expecting that both approaches are technically equivalent and in this case one might argue that the syntactical simplification is a big advantage. I guess you favor the old-fashioned way for technical reasons (which I was not aware of)... – bluenote10 Mar 12 '14 at 18:15
  • 1
    @bluenote10 - Futures generally run on thread pools that do not scale to the size of all available threads, and have additional overhead. When choosing between a more expensive solution that uses a more limited resource, and less expensive one that uses a less limited resource, I tend to choose the less limited one. – Rex Kerr Mar 12 '14 at 21:35
7

spawn is good but note that your sample code works in Scala too:

new Thread(new Runnable() {
  override def run() {
    while (true) { 
      Thread.sleep(1000);
      // clear the cache's old entries
    }
  }
}).start();

Just clean it up with an implicit conversion:

implicit def funcToRunnable(f: => ()) = new Runnable() { override def run() { f() } }

new Thread{
  while(true) {
    Thread.sleep(1000);
    // blah
  }
}.start()
Bill
  • 44,502
  • 24
  • 122
  • 213
  • In my test (Scala 2.10.3) the implicit version is blocking, but the first is not. –  Jun 30 '14 at 18:51
  • @davips Are you sure that the `f` parameter to `funcToRunnable` is lazy? – Bill Jun 30 '14 at 19:19
  • Intellij was complaining about `f: => ()` so I put `f: => Unit`. Should be there any difference? –  Jul 01 '14 at 09:26
5

With Actors without tying up a thread:

import actors.{TIMEOUT, Actor}
import actors.Actor._

private case class Ping( client: Actor, update: Int )
private case class Pulse()
case class Subscribe( actor: Actor )
case class Unsubscribe( actor: Actor )

class PulseActor extends Actor {
  def act = eventloop {
        case ping: Ping => { sleep(ping.update); ping.client ! Pulse }
  }
  def sleep(millis: Long) =
    receiveWithin(millis) {
      case TIMEOUT =>
  }
}

class ServiceActor extends Actor {

  var observers: Set[Actor] = Set.empty
  val pulseactor = new PulseActor
  val update = 2000

  def act = {
    pulseactor.start
    pulseactor ! new Ping( this, update )
    loop {
      react {
        case sub: Subscribe => observers += sub.actor
        case unsub: Unsubscribe => observers -= unsub.actor
        case Pulse => pulse
      }
    }
  }


  def pulse {  
    //cpuload = CPUprofile.getCPUload.getOrElse{ List(0.0) }  //real work
    observers foreach { observer => observer ! "CPUloadReport( cpuload )" }
    pulseactor ! Ping(this, update)
  }
}

object Exercise extends App {
  val deamon = new ServiceActor
  deamon.start
}
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
Johan Prinsloo
  • 1,188
  • 9
  • 9
4

As of Scala 2.11.x, Akka actors seems to be the best way to do this IMHO. First create a task scheduling library:

import akka.actor.ActorSystem
import scala.language.postfixOps
import scala.concurrent.duration._
val actorSystem = ActorSystem()
val scheduler = actorSystem.scheduler
implicit val executor = actorSystem.dispatcher

// do once after period millis
def doOnce(fn: => Unit, period:Long) = scheduler.scheduleOnce(period milliseconds)(fn) 
// do regularly every period millis starting now
def doRegularly(fn: => Unit, period:Long) = scheduler.schedule(0 seconds, period milliseconds)(fn)
// do regularly every period millis if whileFn is true, starting now 
def doWhile(fn: => Unit, whileFn: => Boolean, period:Long) {
 if (whileFn) {
    fn
    doOnce(doWhile(fn, whileFn, period), period)
 }
}

Then use this as:

doRegularly({
  println("hello world!")
}, 1000) // repeat every 1000 millisecs

doWhile({
  println("Sleeping!")
}, whileDaylight, 1000) // repeat every 1000 millisecs whileDaylight is true
Jus12
  • 17,824
  • 28
  • 99
  • 157