Thursday 13 October 2011

Scala Actors and Estragon's Bad Memory


Dear Junior

The event-based actor model in Scala is obviously so much more memory-efficient than the thread-based, so there must be a catch somewhere.  There sure is, the price we pay is that the code does not always behave in the way we intuitively expect. And unfortunately the coding model does not shield us completely from those situations.

The reason I think this is important is that I want to walk the road towards Akka. Once we get there it will be obvious why Akka’s design give us both an efficient runtime model and a carefully guiding programming model.

Unintuitive Effects of Event-Based Model

Let us return to the programming model of event-based actors in Scala standard library, and the things that might baffle us.

One of the things that might happen is that inside one instance of actor, consecutive lines of code might be executed by different threads. That is not what we expect.

Let us pick apart an event-based actor to see what is going on, and the same with a thread-based actor – just for reference.

Dissecting Thread-Based Vladimir

To see how that can happen, let us start with a simple thread-based actor – our dear friend Vladimir. In a small script, we create an actor, start it and send it the message (Godot) that it is waiting for. OK, in the play Waiting for Godot, the point is that Godot never shows up, but let us be nice to poor Vladimir.

object vladimirwaitandrun extends Application {
  def T() = "T" + Thread.currentThread().getId
  println("Creating actor " + T)
  val vlad = new Vladimir(42)
  println("Starting actor " + T)
  vlad.start()
  println("Sending Godot message " + T)
  vlad ! Godot
  println("Finished script " + T())
}

The Godot-waiting actor Vladimir is implemented as a subclass to “actors.Actor” of the Scala standard library.

class Vladimir(id : Int) extends Actor {
  def T = "T" + Thread.currentThread.getId
  def name: String = "Vladimir" + id

  def act() {
    println(name + " is waiting " + T)
    receive {
      case Godot =>
        println(name + " saw Godot arrive! " + T)
    }
  }
}

All set up – let us run the script.

danbj$ scala godot.vladimirwaitandrun
Creating actor T1
Starting actor T1
Vladimir42 is waiting T11
Sending Godot message T1
Finished script T1
Vladimir42 saw Godot arrive! T11

First we note that the script and the actor are run by different threads: T1 and T11 respectively – no surprise. We also note that both lines of Vladimir where run by the same thread. No surprise that either, the thread-based model gives each actor a thread and when the actor pauses (waiting for Godot), the thread pauses.
But let us walk through this just to see the difference when we come to the event-based model.
  • An actor of the class Vladimir is created and started – its “act” method start executing in a thread of its own (T11) starting with a print.
  • The actor executes the method “receive” (still in thread 11). The call to receive takes an argument, which is the so-called “message handler” – a code-block to be used when matching the incoming message. To be precise, the argument is an anonymously defined function, which is passed as the argument to “receive”.  
  • As there is no message in the actor’s mailbox, “receive” puts the thread (T11) to sleep. 
  • Message “Godot” is dropped into Vladimir’s mailbox (by T1). Waiting thread T11 is notified. Thereafter the script finishes.
  • T11 wakes up and starts applying the message-handler to the arrived message. There is a match in the (only) case-clause and T11 prints “Vladimir42 saw Godot arrive! T11”
  • Execution of message handler is finished. As there is no more code in “act” the thread returns.

OK, there are more subtleties going on, but this will do for now.

Dissecting Event-Based Estragon

Now let us look at the same thing happening with an event-based actor: our dear friend Estragon.

object estragonwaitandrun extends Application {
  def T() = "T" + Thread.currentThread().getId
  println("Creating actor " + T)
  val estragon = new Estragon(42)
  println("Starting actor " + T)
  estragon.start()
  println("Sending Godot message " + T)
  estragon ! Godot
  println("Finished script " + T)
}

The Godot-waiting actor Estragon is also implemented as a subclass to “actors.Actor”, and the only difference is that it uses another method for awaiting a message in the mailbox. Instead of “receive” it uses “react”.

class Estragon(id : Int) extends Actor {
  def T = "T" + Thread.currentThread.getId
  def name: String = "Estragon" + id

  def act() {
    println(name + " is waiting " + T)
    react {
      case Godot =>
        println(name + " saw Godot arrive! " + T)
    }
  }
}

All set up. Let us run this.

danbj$ scala godot.estragonwaitandrun
Creating actor T1
Starting actor T1
Estragon42 is waiting T10
Sending Godot message T1
Finished script T1
Estragon42 saw Godot arrive! T13

Now, let us walk through this run and see what actually happened.
  • An actor of the class Estragon is created and started. A thread (T10) is taken from the thread pool and connected to the actor. The thread start running the “act” method, which starts with a print.
  • The actor executes the method “react” (still in T10). The call to react takes an argument, which is the so-called “message handler” – a code-block to be used when matching the incoming message. To be precise, the argument is an anonymously defined function, which is passed as the argument to “react”. 
  • As there is no message in the actor’s mailbox, “react” disconnects the thread from the actor. The message-handler is registered at the event handler. The thread goes back to the thread pool.
  • Message “Godot” is dropped into Estragon’s mailbox from the script (by T1). The event-handler is notified. The script thereafter finishes.
  • The event-handler picks an available thread (T13) from the thread pool and connects it with the actor. The thread is given the message-handler to run and starts applying the message-handler to the arrived message. There is a match in the case-clause and T13 prints “Estragon42 saw Godot …”
  • Execution of message handler is finished. Thread is disconnected and goes back to pool.

Note that there are two different threads (T10 and T13) involved in executing the actor Estragon42. Having a pool of threads does not only mean that one thread can serve many actors (thus conserving resources). It does also mean that different threads might be involved in running the same actor during its lifespan. 

To be honest, I must admit that I did run the script a few times before I got a run with different threads in “is waiting” and “saw Godot arrive”. The allocation of threads is non-deterministic from the point of view of the program, and the first few runs happened to reuse same thread in both phases – but that would not serve to make my point.

The Difference in Short

Let us focus on the core difference between these two examples; first thread-based Vladimir.

    println(name + " is waiting " + T)
    receive {
      case Godot =>
        println(name + " saw Godot arrive! " + T)
    }

Here the same thread (T10, marked as green), execute the consecutive lines. It executes the println and the receive, makes a small pause, and finish with the matching case clause and the last println.

This is execution of code as we learned in Programming 101.

Now, time for event-based Estragon

    println(name + " is waiting " + T)
    react {
      case Godot =>
        println(name + " saw Godot arrive! " + T)
    }

Here two threads are involved. First one (marked blue) execute println and react, ending with registering the message-handler. Then at a later point of time some other thread (marked purple) executes the case-clause and the last println.

The result is that consecutive lines of code inside the same actor object is executed by different threads.

Not what we learned in Programming 101.

Does it Matter?

OK, but does it matter? Unfortunately there are situations where this makes a difference for us as programmers. For example, many security frameworks take user credentials of the authenticated user and stuff it into thread locals. In that way the credentials need not to be passed around explicitly but can be fetched from the thread when needed. Alas, that does not work if the code “suddenly changes horses midrace”.

There are also other situations where the code behaves in unintuitive ways due to this “thread switching” and where the programming model does not shield us programmers from strange effects and risk of making errors. More on that later. 

Estragon’s Bad Memory

On a side not the difference in execution model can also explain one aspect of the play Waiting for Godot. In the play, Estragon suffers from a severe memory condition. When the Act II starts on the morning of the second day, it seems like Estragon has no recollection at all from what happened in Act I the previous day. This is enormously frustrating for his companion-in-waiting Vladimir, who clearly remembers how they waited in vain for Godot to show up.

Now given the knowledge about threading it is obvious why Vladimir remembers the previous day. Thread-based Vladimir is in Act II connected to the same thread of execution as in Act I – so the events in Act I happened to “the same memory-line” as Act II. Event-based Estragon on the other hand is not necessarily connected to the same thread in Act II as he was in Act I, so Estragon in Act II is not “the same memory-line” as Estragon in Act I. In a way Estragon experience the same situations as a person with multiple-personality disorder. Even if it is the same Estragon-body (object, actor), it is not the same Estragon-mind (thread) from time to time.

That might be an explanation for Estragon’s bad memory. It would be interesting to diagnose it more closely, like if we could probe his mind for what is going on from time to time.

Yours
   Dan