Shahzad Bhatti Welcome to my ramblings and rants!

November 22, 2008

Implementing Actor-based message passing using Object-oriented methods

Filed under: Computing — admin @ 11:01 am

I wrote about use of actor based programming for parallel and concurrent programming previously [ 1 , 2 ], where an actor keeps its own thread of execution with a mailbox. Actors communicates to other actors by sending messages that are delivered to its mailbox. In this model, the message passing takes literal form rather than method invocation. I studied Actor based parallel computing in my post graduate research on parallel and distributed field. I learned message passing systems such as Actors, MPI, MPL were much more scalable than shared memory. This describes popularity of languages like Erlang and Scala that has adopted Actor model to tackle concurrency (object-oriented nature in Erlang). According to Ralph Johnson concurrent Erlang is object oriented. Alan Kay has also argued that message passing is more important than objects in object-oriented programming and regrets that he chose the term “object-oriented” instead of “message-passing”. Even Joe Armstrong, who generally dislikes object oriented programming admits similarity between object-oriented programming and Erlang’s message passing.

However, despite effectiveness of message passing in new era of concurrency, I find that pure message passing is a bit intimidating to an average programmer. In this blog, I will show how an object-oriented methods can be used to abstract actor-based message passing. The primary benefit of message passing alongside with immutability is its support of concurrency so the following example will demonstrate use of message passing in multiple threads. Let’s suppose, we are designing a simple chat service to send and receive messages and the message looks like following:

Java

Following is an interface for the chat service:

Java

Note that above interface uses “@Asynchronous” annotation for “sendMessage” and “clear” methods. One of the benefit of message-passing is that you can optionally send asynchronous messages. So I defined an annotation to declare a particular method as asynchronous, e.g.

Java
Following code implements the chat service in non-thread-safe fashion:
Java

Note that above code cannot be used in multi-threading environment. If we were building thread-safe service using Java, we would have to add synchronization or locking such as:

Java
Above code demonstrates use of composition to convert a non-thread-safe class into a thread-safe class.

Now the meat of this library is following factory class that converts any Java object into an actor:

Java
The ActoryFactory uses reflection and proxy features of Java. The client code creates an actor by invoking
Java
      
The create method instantiates a blocking queue that serves as mailbox for the actor and then starts a thread. The create method then instantiates InvocationHandler that intercepts all methods. Finally, the proxy object is returned to the client. When the client invokes any method it is intercepted by the proxy, which then sends the message to the mailbox of the actor. The proxy also checks if the method i defined as asynchronous then it does not wait for the reply. The thread simply waits until there is a message in the mailbox. The message for the actor is defined in MethodRequest that encapsulates reflection information to invoke a method. The actor thread invokes the method using reflection and puts back reply in the queue supplied by the proxy. The proxy waits for the reply and then sends back the reply back to the client. As an actor serves one request at a time, there is no need for locking or synchronization.

Following code demonstrate client test code:

Java
Above class demonstrates a variety of way you can instantiate service class, e.g. by simply invoking the constructor, using reflection and using actors. Note that you cannot simply run non-thread-safe implementation because it would produce incorrect results. For each type of service, the test creates 100 threads that try to send and receive messages. By the end of each test, 200,000 messages are sent and retrieved. Following are runtimes for the service invocation:
 Completed thread-safe direct in 286 millis
 Completed Actor model in 1412 millis
 Completed thread-safe reflection in 693 millis

As expected, using builtin synchronization yields the fastest response, reflection adds some overhead and finally actor based communication adds considerable more overhead. One of the feature of Erlang is its support of seamless networking support. Using an abstraction layer as above can easily be enhanced to start an actor on remote machine. Though, in that case the service will only exist on the remote server. As threads in Java are natives and map to light-weight process, they are much more heavy weight than process in Erlang, which only consumes 300 bytes per process. I have found that native threads are more suitable for CPU-bound processing and green or user-based threads suit well for IO-bound processing. In the end, biggest gain of above design from programmer’s perspective is that the client code looks exactly like any other object oriented and unlike Erlang you get real type safety in message passing. Another big advantage is use of polymorphism, above technique uses dependency inversion principle to interface and implementation separate, thus actual implementation can be changed as needed.

You can download all code from here

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress