Software Secret Weapons™


 
Doug Lea is a Grandfather of all Scala Actors
by Pavel Simakov on 2008-04-03 00:57:55 under Great People, view comments
Bookmark and Share
 


The Context

concurrency.jpg

I am going over various aspects of Scala programming language. The basic language features are very attractive so is it's ability to natively interop with all of my other Java code. In couple of talks and presentations I felt a vibe that Scala Actors are magical things that make concurrency easy. Some of the statements went as far as to say that Scala Actors can help us to easily take advantage of multi core processors that are coming in the near future.

Is this true? What kind of exciting stuff can be done with Scala Actors? Is there something that I can get done in Scala that I can't get done in Java? I will talk about all of it here. You will also learn how Doug Lea became a grandfather of all Scala Actors. As a supplement to this discussion you can download a complete Eclipse project that has both Scala and Java code discussed.

Ping Pong Messaging in Scala

As a newbie to Scala I have looked around for the examples of Actors. One clear illustrative Scala Actors tutorial was finally found credits to Philipp Haller (who is the contributor to scala.actors package itself). There are basically two actors Ping and Pong that exchange messages. The Ping Pong messaging example in Scala almost exactly as Philipp Haller is provided in Appendix A of this post. This example is quite self explanatory and shows how Scala Actors are typically used. Please read the entire original post for more details on how Scala Actors work if you have trouble following this abridged example.

The only thing I would change is to declare the message classes directly and  separately from Actors. Currently it reads "pong ! Ping", so we are sending an object Ping to an object pong, but the object Ping is the Actor in itself... So we are in fact sending Actors to other Actors as messages, which feels weird to me. It helps me personally (and hope some of you too) to separate Actors from messages and simply say "pong ! PingMsg".

Ping Pong Messaging in Java

I found that re-implementing something in the language  I already know helps me to get a good feel for the real issues. Can the same be done in  Java? Sure. Yes, there is much more verbosity (30% more lines of code). Yes, elegance is lost. Yes, it is not cool. However, it is quite possible. In about 1 hours I was able to reproduce quite similar Java Actors implementation shown in Appendix B.

To complete the proof of concept I had to build couple of supporting classes. There are base classes needed: the Actor class and the Message class. The complete runtime (just one thread rather than a complete connection pool for now) is implemented in the MessageBus class. In Java example you see the explicit calls to the message bus initialization; the same exists inside Scala Actors code, but invoked implicitly. You can also see how I declare message classes directly.

Scala Actors use Doug Lea's Fork and Join Tasks (FJT)

Originally written by Doug Lea and released into the public domain FJT library was developed as early as 1999 - almost 10 yeas ago! The introduction to FJT package can be found here. FJT classes are not parts of Actors, but they are distributed all along in the package scala.actors of scala-library.jar. Why are they there?

It turns out that Scala Actors execute message passing using FJT classes written by Doug Lea. This is what is going on when you try to send a message to Actor asynchronously using "pong ! Ping":

  • Actor class (Scala) has new operator defined "!" that allows asynchronous message passing to this actor instance
    	def !(msg: Any) {
        		send(msg, Actor.self)
      	}	
      	
  • Actor class (Scala) defines send() method that passes a message and the continuation (aka future, aka completion point as I like to call it) into the Scheduler (Scala)
    	def send(msg: Any, replyTo: OutputChannel[Any]) = synchronized {
    	    ...
    	    Scheduler.execute(new Reaction(this, continuation, msg))
    	    ...
    	}
    	
  • The Scheduler class (Scala) queues the tasks and calls FJTaskScheduler2 class (Scala) that further uses FJTaskRunnerGroup class (Java) to get some threads and execute the task
  • Control returns to the client and there seems to be no way to wait for the reply

This is all that happens from the sender perspective. Quite simple conceptually, but syntactically elegant ("pong ! Ping") due to Scala's partial, closure and lambda function capabilities.

Now the receiver (or the Actor) perspective. There two different ways to process messages when you are an Actor: the receive() and the react(). When receive() is called the message is pulled out of the queue and execute in the caller thread. When react() is called the message is pulled out of the queue and given to the above scheduler for execution by one of the FJT threads.

There is one (hopefully just one) thing that I don't know. Can a sender wait for the response to a message sent asynchronously via "pong ! Ping"?

The Final Word

This quick look into Scala Actors is very illustrative. Here are my personal takeaways:

  • 1000 lines of code can change the world
  • source code is there - go and read it when in doubt on how things work
  • pay attention to fundamentals; threading is not to be taken lightly; read Doug Lea's book if you have anything to do with threading
  • remember that Scala does not use magic, but relies on conventional good software engineering; rational software engineering can be conducted in any language
  • you can't make "pong ! Ping" work in Java; Scala can definitely do DSL's or at least significantly reduce verbosity over Java
  • Scala is Java

This is not all. There are concerning comments that I have to make now.

First of all, personally, I would like to see a cleaner separation between Scala as language (and a compiler) and Scala as collection of libraries. The Actors in Scala are really not a part of the core Scala language, but rather a library and it would be better to provide scala-actors.jar and scala-lang.jar as separately versioned artifacts.

Secondly, if you remember Win32 API you realize that asynchronous messaging is not new. The whole Windows GUI subsystem is based on message passing. Just go to MSND and search for postMessage or peekMessage if you need a refresher. I had to write a lot of Win 32 API code back in 1997. I still have grey hairs from the thread affinity of HWND handles, MsgWaitForMultipleObjectsEx and other things of that nature. All of it makes me think that Scala Actors are not sufficient for enterprise scale asynchronous messaging. Once again Scala has a good set of language features and very good performance. But the libraries that come with Scala, including Actors, have to be reviewed carefully to ensure that they meet your enterprise level of you quality & maturity expectations. For some things I will still pick Doug Lea's 1000 lines of century old code...

Appendix A. Source code for PingPongScala.scala

import scala.actors.Actor;
import scala.actors.Actor._;

package com.oy.shared.scample.scala {

	case object Ping
	case object Pong
	case object Stop
	
	class Ping(count: int, pong: Actor) extends Actor {
	  def act() {
	    var pingsLeft = count - 1
	    pong ! Ping
	    while (true) {
	      receive {
	        case Pong =>
	          if (pingsLeft % 1000 == 0)
	            Console.println("Ping: pong")
	          if (pingsLeft > 0) {
	            pong ! Ping
	            pingsLeft -= 1
	          } else {
	            Console.println("Ping: stop")
	            pong ! Stop
	            exit()
	          }
	      }
	    }
	  }
	}
	
	class Pong extends Actor {
	  def act() {
	    var pongCount = 0
	    while (true) {
	      receive {
	        case Ping =>
	          if (pongCount % 1000 == 0)
	            Console.println("Pong: ping "+pongCount)
	          sender ! Pong
	          pongCount = pongCount + 1
	        case Stop =>
	          Console.println("Pong: stop")
	          exit()
	      }
	    }
	  }
	}
	  
	object PingPongScala extends Application {
		def run(){
		  val pong = new Pong
		  val ping = new Ping(100000, pong)
		  ping.start
		  pong.start
		}
	}

}

Appendix B. Source code for PingPongJava.java

package com.oy.shared.scample.java;

import com.oy.shared.scample.actor.Actor;
import com.oy.shared.scample.actor.Message;
import com.oy.shared.scample.actor.MessageBus;

class PingMsg extends Message {
	final Ping sender;
	public PingMsg(Ping sender){
		this.sender = sender;
	}
}

class PongMsg extends Message {
	final Pong sender;
	public PongMsg(Pong sender){
		this.sender = sender;
	}
}

class StopMsg extends Message {
	
}	

class Ping extends Actor {
	private Pong pong;
	private int pingsLeft;
	
	public Ping(int count, Pong pong) {
		this.pong = pong;
		this.pingsLeft = count - 1;
	}
	
	public void start(){
		super.start();
		
		PingMsg pingMsg = new PingMsg(this);
		pong.postMessage(pingMsg);
	}
	
	public void react(Message msg) {
		if (msg instanceof PongMsg) {
			if (pingsLeft % 1000 == 0) {
				System.out.println("Ping: pong");
			}
			if (pingsLeft > 0) { 
				PingMsg pingMsg = new PingMsg(this);
				pong.postMessage(pingMsg);
				pingsLeft -= 1;
			} else {
				System.out.println("Ping: stop");
				pong.postMessage(new StopMsg());
				stop();
			}
		}
	}
}

class Pong extends Actor {
	private int pongCount;
	
	public void react(Message msg){
		if (msg instanceof PingMsg){
			PingMsg pingMsg = (PingMsg) msg;
			if (pongCount % 1000 == 0) { 
	            		System.out.println("Pong: ping " + pongCount);
			}
			
			PongMsg pongMsg = new PongMsg(this);
			pingMsg.sender.postMessage(pongMsg);
	        	pongCount = pongCount + 1;
	        
	        	return;
		}
		
		if (msg instanceof StopMsg){
			System.out.println("Pong: stop");
			stop();
			
			return;
		}
	}
}

public class PingPongJava {
	public static void run(){
		MessageBus mbus = new MessageBus();
		mbus.start();
		
		Pong pong = new Pong();
		Ping ping = new Ping(100000, pong);
		ping.start();
		pong.start();
		    
		mbus.stopWhenActorsFinish();
	}
}

Advanced tactics like search engine marketing and accepting online payments are used by business savvy voip providers.

Comments (5)

  • Comment by jau — April 3, 2008 @ 6:50 am

    I think you can wait for response using the “pong !? Ping”? syntax.

  • Comment by Alex Miller — April 3, 2008 @ 11:29 am

    FYI, the fork-join framework is slated to be included in Java 7 as part of the latest JSR 166 extension.

  • Comment by Franco Lombardo — April 3, 2008 @ 1:34 pm

    Good post! If someone is interested in a brief description of the whole Scala language, with a special look to Actors could take a look to http://stacktrace.it/articoli/2008/03/il-linguaggio-scala/.
    The article is in Italian, but I will publish an English version soon.

    Bye

    Franco

  • Comment by Tom — April 4, 2008 @ 12:09 pm

    I like lots of Scala, but I don’t like operators like “!”. That’s the kind of idea that makes me wary of it. Nice closure block structures rock, though, and I’ve come to like pattern matching in many cases. But “send” means so much more to me than “!”.

  • Comment by Gabriel C. — April 5, 2008 @ 7:25 pm

    I bet you can define a trait like:
    trait MySend extends Actor{
    def send(msg:Any):Unit= this!msg
    }
    then, instead of new Actor you can do new Actor with MySend, and voila, you have your actor.send !
    This is one of the things I really appreciate of Scala…


Leave a comment


 
Dog Emotional 2010 Calendar Dog Emotional Mousepad Dog Fashionable 2010 Calendar Dog Fashionable Mousepad

Copyright © 2004-2010 by Pavel Simakov
any conclusions, recommendations, ideas, thoughts or the source code presented on this site are my own and do not reflect a official opinion of my current or past employers, partners or clients
SourceForge.net Logo