Статьи

Истинное искусство функциональной облачной рекурсии с GridGain 3.0

 

Как я уже упоминал в моем предыдущем блоге, GridGain 3.0 практически изменил наш взгляд на облачное программирование. GridGain всегда был простым и естественным в использовании, но после последней версии 2.1 этого уже не хватало. Мы продолжали думать о том, как сделать наш продукт еще более естественным и мощным. Что ж, добавление компонента Data Grid в GridGain 3.0 определенно помогло, но я думаю, что самым большим и самым мощным изменением для нас был значительный сдвиг парадигмы в сторону функционального программирования (FP) с богатыми и мощными API. Функциональный подход для API просто подходит так естественно, я удивлен, что мы не думали об этом раньше (ну … чтение книг по Scala определенно помогло :). В GridGain 3.0 API разбогател, а код стал лаконичным.

Посмотрите, например, на то, как вы можете * рекурсивно * вычислить последовательность Фибоначчи для числа
10 в GridGain 3.0 (это не самая эффективная реализация, но пока что со мной):

final Grid g = G.start(); // Start grid.

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);

Что следует отметить в приведенном выше фрагменте кода:

  1. GridClosureX — это просто функция, которая будет выполняться в удаленной сетке или облаке (суффикс «X» означает, что она вызывает GridException).
  2. Нет этапа развертывания — GridGain автоматически развертывает ваш код на участвующих узлах по требованию (довольно круто).
  3. Мы повторно используем одну и ту же переменную сетки «g» в локальном и удаленном коде (даже круче, но она становится лучше).
  4. Обратите внимание, как мы повторно выполняем то же самое закрытие от удаленных узлов * рекурсивно * , передавая метод this в метод g.call (..) !!!

Я надеюсь, что вы уже заинтригованы, но приведенный выше пример, каким бы красивым он ни был, не очень полезен или эффективен. Узлы могут рекурсивно вычислять число Фибоначчи для одного и того же числа более одного раза в течение одного и того же выполнения. Кроме того, метод возвращает целое число, что не очень практично, так как числа Фибоначчи очень быстро растут.

Давайте немного увлечемся и введем кеширование вычисленных чисел Фибоначчи на удаленных узлах. Также давайте переключимся на использование BigInteger, чтобы мы могли обрабатывать действительно большие числа:

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);

Этот фрагмент кода очень похож на первый, за исключением того, что он кэширует уже вычисленные значения непосредственно на удаленных узлах, поэтому он становится умнее по мере продвижения. Если вы запустите его дважды для одного и того же значения, во второй раз вообще не произойдет рекурсии, и вы сразу получите результат из локального хранилища узлов. Все, что нам нужно сделать сейчас, это просто запустить несколько узлов сетки и попробовать. Результат для Фибоначчи (100)«354224848179261915075» .

Теперь я хочу, чтобы вы остановились на секунду и подумали о том, чего нам удалось достичь всего несколькими строками кода выше.

Этот пример, наряду со многими другими, поставляется с GridGain . Я приглашаю вас скачать его и убедиться в этом.

От http://gridgain.blogspot.com/2010/08/true-art-of-functional-cloud-recursion.html