True Art Of Functional Cloud Recursion with GridGain 3.0
Join the DZone community and get the full member experience.
Join For Freeas i mentioned in my previous blog, gridgain 3.0 practically changed the way we think about cloud programming. gridgain has always been simple and natural to use, but after the last 2.1 release this just was not enough anymore. we kept thinking on how to make our product even more natural and more powerful. well, the addition of data grid component in gridgain 3.0 definitely helped, but i think the biggest and most powerful change for us was a significant paradigm shift towards functional programming (fp) with rich and powerful apis. the functional approach for apis just fits so naturally, i am surprised we have not thought about it before (well... reading books on scala definitely helped :). in gridgain 3.0 the api's got rich, and the code got terse.
take a look for example at how you can *recursively* calculate fibonacci sequence for number 10 in gridgain 3.0 (this is not the most effective implementation, but bare with me for now):
final grid g = g.start(); // start grid.things to notice in the above coding snippet:
int fib = g.call(unicast, new gridclosurex<integer, integer>() {
@override public integer applyx(integer n) throws gridexception {
return n == 0 ? 0 : n <= 2 ? 1 :
g.call(unicast, this, n - 1) + g.call(unicast, this, n - 2);
}
}, 10);
- gridclosurex is just a function which will be executed on the remote grid or cloud (suffix 'x' means that it throws gridexception).
- there is no deployment step - gridgain auto-deploys your code on participating nodes on-demand (pretty cool).
- we are reusing the same grid variable "g" in local and remote code (even cooler, but it gets better).
- note how we are re-executing the same closure from remote nodes *recursively* by passing " this" into "g.call(..)" method!!!
let's get a little fancier and introduce caching of calculated fibonacci numbers on remote nodes. also let's switch to using biginteger so we can handle really large numbers:
biginteger fib = g.call(unicast, new gridclosurex<long, biginteger>() {
@override public biginteger applyx(long n) throws gridexception {
system.out.println("starting fibonacci execution for number: " + n);
// make sure n is not negative.
n = math.abs(n);
if (n == 0) {
return biginteger.zero;
}
if (n <= 2) {
return biginteger.one;
}
// node-local storage is provided by grid.nodelocal() method.
gridnodelocal<long, biginteger> nodelocal = g.nodelocal();
// check if value is cached in node-local store first.
biginteger n1 = nodelocal.get(n - 1);
// if value is not cached in node-local store, then
// compute it and cache it.
if (n1 == null) {
// nested recursive distributed execution on the grid.
nodelocal.putifabsent(n - 1, n1 = g.call(unicast, this, n - 1, p));
}
// check if value is cached in node-local store first.
biginteger n2 = nodelocal.get(n - 2);
// if value is not cached in node-local store, then
// compute it and cache it.
if (n2 == null) {
// nested recursive distributed execution on the grid.
nodelocal.putifabsent(n - 2, n2 = g.call(unicast, this, n - 2, p));
}
return n1.add(n2);
}
}, 100);
this code snippet is pretty similar to the first one, except that it caches already calculated values directly on remote nodes, so it gets smarter as it progresses. if you run it twice for the same value, no recursion will happen the second time at all, and you will get result immediately from node-local store. all we need to do now is just startup a few grid nodes and give it a go. the result for
fibonacci(100)
is
'354224848179261915075'
by the way.
now i want you to stop for a second and think about what we have been able to achieve just in a few lines of code above.
this example, along with many others, is shipped with
gridgain
. i invite you to
download
it and see it for yourself.
from
http://gridgain.blogspot.com/2010/08/true-art-of-functional-cloud-recursion.html
Opinions expressed by DZone contributors are their own.
Comments