Monday, October 26, 2009

From the Future, another angle on concurrency


(Warning contains graphic abuse of the type system in Scala code).

In languages like Scala, and of course Erlang, a lot of the focus is on Actors and message passing as a way to achieve concurrency and parallelism without using share-memory threads.

This is great, works awesome, and I love it. But its not all of the story. Sometimes you have a need to "fan out" a whole lot of slow/blocking things, and then join it all back together later on - a classic example used is hitting up a lot of remote resources at once (and very easy to do). Or, perhaps you have quite a few processors available, and a few computationally heavy tasks to do etc...

Well despite the bashing multi-threaded programming gets, the reality is threads are here to stay. But they are hard and I can't really do then.

Thankfully there are those smarter than me that have built lovely frameworks that take away most of the management of threads from us mortals (such as Doug Lea and java.util.concurrent on the JVM, and Grand Central Dispatch on OS-X - (and soon to be in BSD !)).

Speaking to Jon Tirsen of Google, he was musing over the idea of a language based around 100% async dispatch where everything was returned as a Future - pretty much the opposite to to lazy languages:

So I looked into java.util.concurrent.Executors - you can create executors (based on thread pools that you don't manage) and pass it "callable" tasks to run asynchronously. The trick is getting results back - this is where Futures come in. So when you submit a task to an executor, it returns a Future immediately - the future is a promise of a value at some point. When you call "get()" on the Future, it then blocks until it has a result (or course, hopefully it already has one). In java, this is understandable cumbersome, but works:

ExecutorService service = ...
Future result = service.submit(new Callable() {
public String call() {
return ... expensive computation ...
}
});

So result is of type Future of T - where T is the type of the real result. You have to call result.get() and then it will block... ugh, crazy... but worth it.

Enter Scala, before creating a whole new language as Jon suggested, I thought I would give ordinary Scala a go:

Wouldn't it be nice to take a piece of code like:

val result = someExpensiveFunction(42)

and make it async, and not worry about Future and all that? Well by the power of greyskull, thunking and implicit conversions this is possible:

val result = future { someExpensiveFunction(42) }

Note that I didn't have to change anything other then wrap future {.. } around it. Now, as Scala has type inference, this looks cleaner, but future is of type Future[T], where T is the return type of someExpensiveFunction. However, due to implicit conversions, we can pretend it isn't - it will return immediately, and you can pass it around, and once it actually needs the value of result, then, and only then will it block (automagically) - hopefully by then it will have its result !

So, how does it work:
object FutureProcess {
val executor = Executors.newCachedThreadPool
implicit def fromFuture[T](future: Future[T]) : T = future.get
def future[T](lambda: => T) : Future[T] =
executor.submit(new Callable[T] { def call=lambda })
}


So the above is all of it.
  1. we create an executor (its in an object so we only have one instance of it, easy). In this case its just a thread pool (but you could size it based on CPU cores if you like).
  2. we have an implicit def, which when it sees a Future of T, but needs T, it will call "get" (ie block and wait for result).
  3. the Future function: take any "block" of code, which returns T, and submit it wrapped in a Callable (nice how compact it is). The only clever bit is the "thunk" - the "=> T" bit - which means it is a parameter which isn't evaluated when it is called, but when it is needed - this is important as it means it isn't evaluated until it is safely submitted to the executor (and thus has a separate thread doing it) and can return immediately.

So the happy result is that all you do is import FutureProcess, and then wrap future { ... } around the bits you want done async, but really, no other code changes. Classic scala, slightly mind bending at the library level, but a breeze to use.

Enjoy.












Wednesday, October 7, 2009

New podcast episode is up

http://asylum.jboss.org/

Still getting the hang of mixing it - more compression needed. And
cowbell. 0% cowbell in this episode, unfortunately.

Posted via email from Michael's posterous

Monday, September 28, 2009

A visual comparison of a java to scala port

... of a single class. In this case port was mechanical, I only did to
avoid mixed java/scala source in the one project (which you can of
course do, but I don't like doing it, and it was just one class).

I didn't change the code really (except for dealing with a null, which
is just too nice with a match).

You can guess which one is which (the scala one still ends up a little
bit shorter, mostly due to the constructor magic) but a whole lot more
pleasing to my eye anyway.

Posted via email from Michael's posterous

Thursday, September 24, 2009

A new podcast

I recently started working on a podcast on all things jboss.org, R&D
related, with Max Andersen and Emmanuel Bernard. I am the only one
without an accent ;)

Editing podcasts is much less fiddly then editing music, but still
takes work and practice.

Content is syndicated through libsyn here: http://asylum.libsyn.com/

It is also available on itunes of course.

Posted via email from Michael's posterous

Wednesday, September 23, 2009

Deltacloud.org...

I recently took a look at Delta Cloud - a good start at providing some
ability to switch "between clouds" or at least work across them
(including "clouds" based on virtualisation managers like RHEV-M from
Red Hat and VMWare).

Rackspace seems pretty sweet, has a nice RESTful style API to manage
stuff, so it was easy to write a driver for deltacloud.org (which I
did):

Get the good stuff here: (should be upstream shortly)
http://github.com/michaelneale/driver-rackspace/

The deltacloud framework itself is a RESTful rails app (and the
"drivers" are written in ruby).

Posted via email from Michael's posterous

Wednesday, September 16, 2009

Infinispan - distributed cache/data grid


One has to have a hobby. Tragically mine is perilously close to work. So as part of learning about Infinispan (a distributed data grid) I created a RESTful server front end for it (in scala, of course), posted about it here.

Tuesday, September 15, 2009

Book review: Dependency Injection


My good friend Dhanji Prasanna from Google recently finished his book on DI practices and patterns. I was given a copy for review - I am by no means a DI expert (barely know what it is).

To be honest I am/was a DI skeptic, I view it as a way to make up for weaknesses of statically typed mainstream languages (such as C# or Java). And thus DI brings in a raft of type unsafety issues, leading to runtime hassles (without the productivity/joy of a dynamically typed or scripting language).

However, the book always circles back to how to solve a problem in a type safe way - were code is more correct (and the compiler verifies it) before any runtime error occurs (any runtime DI activity is for performance and functional) - and leads to less surprises and biting in the ass.

The style of the book seems to be to show the problem in its raw form, using various tricks to try and get around it, failing and then introducing a DI framework, and showing the various solutions with the framework. Each section usually resolves to a simple solution that provides compile time type safety - I can reasonably assume this is Dhanji's intent, to gently "show you the way" - ie "the right way" of doing it. Dhanji is a Guice committer, so of course the best side of Guice is shown, but I believe he also does the best with the other frameworks he has a lot of experience with (personally I admire Guice a lot, I think it has learned from all the frameworks before it and been battle hardened).

Well if you do large scale java apps, you probably want to have someone on the team have this book.