0
votes

I'm completely new to this, but here's a Scala actor that's created with my class and only lives to generate messages for other actors. I would like it to wake up every second, gather some metrics, ship them off to other actors, and go back to sleep. When terminating the application, I need to send this actor a message to quit

class Node() {
  println("A new Node is being constructed")
  val load_monitor: Actor = actor {
    val s: Sigar = new Sigar
    while (true) {
      Thread.sleep(1000);

      // Will be replaced with something like 
      // load_manager | s.getCpuSystem
      println(s.getCpuPerc)

      self.receiveWithin(100) { 
        case "EXIT" => exit() 
        case TIMEOUT => {}
      } 
    }
  }

  // Other Node code below...
}

This seems to work, but I don't have confidence it's correct. Is calling Thread.sleep smart? If this is a full thread, I now have a sleeping thread. If this is an event, have I now blocked some event processing queue? Can I use the receive/react stuff to do this more properly? I'm having trouble understanding if receive/react effectively stops the execution of an actor, which means I could not wake up every second to check metrics. I've also considered the following code, but I don't know if it is any better than the above code!

class Node() {
  println("A new Node is being constructed")
  val load_monitor: Actor = actor {
    val s: Sigar = new Sigar
    while (true) {
      self.receiveWithin(1000) { 
        case "EXIT" => exit() 
        // Will be replaced with something like 
        // load_manager | s.getCpuSystem
        case TIMEOUT => println(s.getCpuPerc)
      } 
    }
  }

  // Other Node code below...
}
3
I am not sure of the answer to this as I am not familiar with Scala Actors, but I suggest checking out Akka (akka.io) which has, for all intents and purposes, replaced Scala Actors as of Scala 2.10.adelbertc
I'm definitely looking into it, but my question here is searching for an understanding of how to use the Actor paradigm, so I don't think switching implementations would help much at this point. Granted, what do I know :-) I'm still a bit confused about if Akka is built on top of scala actors, their FAQ is pretty blank on the "what is akka" questionHamy
No, akka is a completely independent implementation and goes way beyond what the scala actors were capable of.drexin

3 Answers

3
votes

First off, I'd highly recommend using Akka which for all intents and purposes, have replaced Scala Actors as of Scala 2.10. Akka is an independent implementation of the Actor paradigm, and is not based off Scala Actors.

That being said, I'm going to base my answer off of Akka 2.x, both because I'm most familiar with Akka 2.x and because it may prove to be more useful to you as Akka is now the de facto Actor implementation for Scala (and perhaps the JVM as a whole).

The Actor paradigm is easy enough to understand - it is based off of two main ideas: encapsulated mutability, and message passing. Each Actor encapsulates it's own state, nothing else should touch the internal state of an Actor other than the Actor itself. Actors communicate via messages. If some Actor A wants to mutate a variable encapsulated inside Actor B (e.g. perhaps A represents a client and B represents the client's bank account), A will send a message to B indicating such - note that B is free to ignore the message.

Actors do not tie up a thread at all times, they only "wake up" when a message is waiting for them in their mailbox. Hence the call to Thread.sleep is not only unnecessary, but not recommended.

In Akka, messages are loosely typed (Any), so you typically want to send messages in the form of case classes (which are not only easy to construct, but also to pattern match on, useful for the receive in Akka Actors).

You can create a scheduler for each Actor that will send itself a message every x seconds (Akka has tools for making this really easy). This message will trigger the Actor to wake up, read a message in the mailbox (which will presumably be the message indicating it should gather the statistics), and act on it.

To broadcast the message to several other Actors, there are many ways to do this. One simple way is to keep some sort of collection of ActorRef (Akka specific) in the metric gathering Actor, and each time the Actor wakes up to gather stats, it simply sends a message to every Actor corresponding to that collection. There are many other ways you can do this.

If you are really interested in using Actors in Scala (or the JVM in general), I highly recommend Derek Wyatt's book Akka Concurrency.

2
votes

Using while(true) and Thread.sleep is not a good idea in actors. You don't wanna block. I would periodically send the actor a message, on which it then reacts.

example:

import scala.actors.Actor

import java.util.Timer
import java.util.TimerTask

case object DoSomething

class MyActor extends Actor {
  def act() {
    loop {
      react {
        case DoSomething =>
          // do measurement
          println(Runtime.getRuntime.freeMemory + " bytes free")

        case 'kill =>
          exit()
      }
    }
  }
}

val actor = new MyActor
actor.start

val timer = new Timer(true)

timer.schedule(new TimerTask {
  def run {
    actor ! DoSomething
  }
}, 1000, 1000)

I would also recommend you to use akka instead. With akka the same thing would look like this (not tested):

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

case object DoSomething

class MyActor extends Actor {

  context.scheduler.schedule(1 second, 1 second) {
    self ! DoSomething
  }

  def receive = {
    case DoSomething =>
      // do measurement
      println(Runtime.getRuntime.freeMemory + " bytes free")
  }
}

val system = new ActorSystem("MySystem")

system.actorOf(Props[MyActor])

To kill an akka actor you can always send it the akka.actor.PoisonPill, this will kill the actor after all remaining messages in the queue have been processed.

1
votes

I'm completely new to this

In this case, as adelbertc says, you really should start with Akka actors, unless you are stuck with requirement to use Scala actors to maintain a legacy application (since Scala actors are deprecated in current Scala version and will be removed in the next one).

Is calling Thread.sleep smart? If this is a full thread, I now have a sleeping thread.

No, if you call Thread.sleep you always have a sleeping thread. Actors don't somehow change the meaning of existing methods!

Your second option is nicer, but receiveWithin means this actor will run in its own thread, better use reactWithin and see this answer.

With Akka actors, you can just use a Scheduler.