Fork me on GitHub

Thursday, February 18, 2010

#Concurrency - Software Transactional Memory in JRuby with Clojure

Still playing with JRuby and concurrency... For me JRuby is one of the best implementations of Ruby VM. It has this amazing property of taking the most boring Java projects and turning them into something exciting. Not that clojure is boring but on the other hand it is one of the most wonderful languages I have worked with. Being a big fan of Lisp Clojure is a dream come true.

This post is about my exploration with JRuby and Clojure more in terms of how to use the Clojure's STM infrastructure. Whenever I find an interesting Java library the first thing I do is to import it into JRuby and play with it for sometime. After working with Clojure I wanted to use its STM in Ruby and finally found time to do it. The code is really crude as it explores very basic functionality of STM. May be as I keep working I will try to build something around this and who knows it can end up as a library for JRuby :)...

Instead of defining STMs myself - Here it is from Wikipedia..
"In computer science, software transactional memory (STM) is a concurrency control mechanism analogous to database transactions for controlling access to shared memory in concurrent computing. It functions as an alternative to lock-based synchronization. A transaction in this context is a piece of code that executes a series of reads and writes to shared memory. These reads and writes logically occur at a single instant in time; intermediate states are not visible to other (successful) transactions."

As most of you know the problem is with sharing the state.. In this example my_account balance. Imagine when two different threads of execution trying to update the value at the same time. Disastrous results may ensue. So the typical approach is locking of the shared resource. Problem with locking is it effectively limits concurrency as well is too hard to get it right. So we have started looking for other models of concurrency. Actors, Dataflow and STMs are some of the popular form. As you see in the example let's say there is a shared resource. If we need to update it we can't update it in a separate context. We need to run this as a part of transaction and as database transactions it is all or nothing.

In Clojure's term a ref can be updated only inside the context of a transaction. Else it will throw IllegalStateException. As well the ref getting updated will not be visible to outside work till the end of the transaction. The transactions are composable which is difficult in cases of threads and locks. Also as the example shows STM is a form of optimistic concurrency. Everyone can update the shared resource but whoever finishes first and commits wins. Others fail because the state now is different from what they started with and they can try.

The code is almost self explanatory and simple. Using clojure STM is pretty simple and straightforward. And this will help us to effectively manage concurrent access of shared resource by multiple threads.

Let me know your thoughts...


Ravindra Jaju said...

Nice post, Sai. Also shows how we can use the best tool for a job, thanks to the JVM. The only thing that leaves me a bit concerned is how we mix Ruby and Clojure - gotta use JRuby, so not portable for all Ruby apps. Is it time to 'declare' JRuby as a super-set language of Ruby and move ahead? Or keep it shackled down to Ruby-compliance-requirements?

It's tricky, and that's where I think Scala + Clojure may be a good mix. Throw away the Java language, and move on with the JVM.

Sai Venkatakrishnan said...

JVM is best as a platform. I have already moved away from using or advocating java as a language. Clojure, Scala and JRuby seem to do a really good job in that.

The one advantage with Java over Ruby is the wealth of infrastructure already available in Java and the amount of work it takes to replicate that :). JRuby runs RubySpec so it will be compatible with other Ruby VMs.

Ravindra Jaju said...

Sure, I was never doubting the compatibility goals of JRuby to the Ruby motherland. I was only wondering if JRuby is being held back due to that.
But thanks to the JVM, atleast I know I can play with and mix many other tools I have on the JVM. We'll need to evolve practical ways around mixing various JVM languages, get general acceptance around them, and start using them in a much more larger and concerted way. :)

Sai Venkatakrishnan said...

I understand the concern. But I don't think JRuby is going to evolve beyond Ruby. It is gonna be a mirror image of MRI with JVM as platform and not as a separate entity itself. That's why I think there is no support for annotations till now as, Ruby as a language doesn't have support for it.