Concurrencia 

Paralelismo


Evolución del Software.
Lo bueno, lo malo, lo necesario e incomodo.




Agenda

  • Características 
  • Evolución y Revolución
  • Moore - Amdahl y Page
  • Concurrencia
  • Paralelismo
  • Scala
  • Clojure

90's



Caracteristicas


  • Mayor Complejidad
  • Nuevas Estructuras
  • Modelar el Dominio
  • Reutilización
  • Objetos

Lenguajes


Simula
Smalltalk
C++
Objective-C
Java
C#
Ruby
... y una bolsa interminable de ellos ...

Thinking in...


OOA & OOD & OOP
UML
Patterns
XP
Agile
DDD
TDD
BDD

Evolucion

Modelado Conceptual
Aumento de la Complejidad
Infraestructura
Diseño Participativo
Reutilizacion

revolucion

Big Data
Cloud 
Integración - Coordinación - Disponibilidad
Tolerancia a fallos
Calidad

Multi-core
GPU

Ley de moore

Tendencia de crecimiento
Velocidad de procesamiento
Capacidad de almacenamiento 
Aumentos exponenciales



Ley de Amdhal

Mejora en la ejecución al aumentar el número de procesadores
Es un modelo matemático que describe la relación entre la aceleración esperada de la implementación paralela de un algoritmo y la implementación serial del mismo algoritmo.


Tendencia

EL MUNDO DEL SOFTWARE ESTA CAMBIANDO INFLUIDO POR LA TENDENCIA EVOLUTIVA DEL HARDWARE



ley de Larry page

"Page's Law is sort of the opposite of Moore's Law," "Page's Law says that every 18 months software becomes twice as slow."

demanda

Productos o Servicios
Usuarios y Usabilidad
Funcionalidad
Confiable, Portable y Eficiente
Mantenimiento
Escalabilidad

En cuanto a las aplicaciones modernas...

escalabilidad

  • Vertical (scaling up) - Concurrencia
  • Horizontal (scaling out) - Distribucion
  • Size - Recursos, Usuarios, Computo
  • Localización
  • Administración 
  • Disponibilidad - Fault Tolerance
  • Performance 



En lineas generales

Se busca desarrollar programas cada vez mas complejos con el uso de múltiples CPUs multicore y hasta incluir GPUs en la computación de procesos con la posibilidad de reducir el tiempo de ejecución de un programa. 

ventajas

Tiempo de computo
Recursos
Acceso simultáneo
Mayor cohesión y menor acoplamiento entre tareas
Ahorro e inversión

desventajas

Programas mas complejos
Ejecuciones no determinísticas
Requiere un mayor grado de especialidad
Código difícil de depurar

determinismo

Algoritmo completamente predictivo si se conocen sus entradas, si estas son iguales producen siempre la misma salida.
Por ejemplo Tuning es una máquina de estado abstracta determinística.

concurrencia

Ejecución de programas de forma no determinística
Necesaria para implementar Paralelismo
Se pueden estar realizando dos o mas operaciones en el mismo tiempo o no. Depende del Paralelismo
Sincronización y Comunicación de ejecución en una o mas CPUs.

Paralelismo

Implica una ejecución simultánea de dos o mas operaciones en el mismo número de CPUs.
Necesita mecanismos de concurrencia para juntar las partes de los cálculos realizados.

Concurrencia y paralelismo

Programacion paralela

Ejecutar programas más rápidos en hardware paralelo

Programacion Concurrente

Manejar y administrar los Threads de ejecución concurrentes de manera explícita

Ambos son demasiados complicados y difíciles de editar, ejecutar y mejorar (bugs too hard)

PPP Grand Challenge 

La necesidad de la computación paralela y concurrente llevada a cabo de manera fácil y segura es llamada PPP (Popular Parallel Programming). Este es el nuevo desafío.


Estamos frente a un nuevo paradigma en el desarrollo del Software?

Pero, por qué es tan importante?

Permite simular una ejecución en un entorno monocore.
Gestionar el acceso seguro a elementos compartidos y secciones críticas.
Garantizar que las operaciones siempre brindan los mismo resultados.
Reducir el tiempo de cómputo en programas de cualquier escala.
Mejora en la administración de los recursos.

El problema principal


non-determinism = parallel processing + mutable state


Non-determinism caused by concurrent threads accessing shared mutable state.


Soluciones

Threads. Locks. States
Sinchronization Blocks
Agents
Actors (base on Erlang)
Shared Memory
STM (Software Transactional Memory)
Futures

Soluciones


Collections:
  • Parallel Collections
  • Distributed Collections


Parallels DSL

Threads


Single Block


En el bloque el Thread se suspende

Threads (add concurrency)


Tiempos de Procesos y latencia

Thread por tarea (dividido en capas). Resultado sincrónico.

Tiempos de procesos y latencia

Paralelismo por capa de procesamiento - Asynchronous and Partial Results From Request/Response to Request Stream/Response Stream

El desafio 

Parallel
Async
Distributed

Cómo hacer uso de la manera más eficiente los recursos multicore, GPUs, Clusters? Cómo manejar eventos asincronicos? Cómo responder frente a los delays y errores?

orientacion a objetos

Objects are characterized by state, identity and behavior
(Booch)
Abandonar la OO? Mantener la descomposición en el Análisis y Diseño
  • Eliminar o reducir el uso de estado mutable
  • Concentrarse en la funcionalidad (behavior)
  • Apoyarse en la estructuras en lugar de las referencias

Programacion Funcional

  • Funciones de primer nivel
  • Closures
  • Asignación simple
  • Evaluación tardía
  • Inferencia de tipos
  • Optimización del tail call
  • Efectos monadic

Programacion funcional

El computo se basa en la evaluación de funciones matemáticas, evitando los programas con estado y datos que pueden ser modificados.

Adoptar una visión más matemática del mundo en el que los programas
están compuestos por numerosas funciones que esperan una determinada
entrada y producen una determinada salida y en ocasiones otras
funciones.

JVM

Lo más relevante de Java es su máquina virtual (JVM)  
Carga y almacenamiento
Aritmética 
Conversión de tipos
Creación y manipulación de objetos
Gestión de pilas (push y pop)
Transferencias de control
Invocación y retorno a métodos
Excepciones

Java

    public class DummyThread extends Thread implements 
        AccessPoint {
        
        public void startListening(Properties props, 
            String interpreterName) {
    	    this.setDaemon(false);
		    this.setName("GarbageCollectorInvoker");
		    this.start();
	    }
        
        public void stopListening() {
    	stop=true;
		synchronized (this){
			notifyAll();
		    }
	    }
        
        public boolean isListening() {
    	return !stop;
	    }
    }

Java


    
public void run() {
    	int interval = 0;
		try{
			
		while(!stop){
			try{
				synchronized (this){
					wait(interval);
					System.gc();					
				}
			}catch(Exception e){
				log.error(e.getMessage());
			}
		}

}

Java


public class SocketEventHandler extends Handler {
public SocketEventHandler(SocketEventHandlersManager mgr){
    	super(mgr);		
}
public void run(){    	
try {	
			Object message = null;
			EventHandlersManager manager = (EventHandlersManager) getManager();
			while (!stopProcessing){
				changeState(Handler.States.WAITING);
				message = manager.getNextMessageToSend();
				if (message!=null){
					this.sendMessageToClient(message);
					changeState(Handler.States.WORKING);
				}
			}
			
		}catch (InterruptedException e) {
		}catch (Exception e) {
		}finally{
			changeState(Handler.States.DEAD);
		}
	}
    }

Scala

Lenguaje de Programación de propósito general
JVM
Orientado a Objetos + Funcional
Sintácticamente mas liviano
Safe and Performant

Java vs Scala


public class Person {
    public final String name;
	public final int age;
	Person(String name, int age){
		this.name = name;
		this.age = age;
	}
}


class Person(val name: String, val age: int)

Java vs Scala


import java.util.ArrayList;
Person[] people;
Person[] minors;
Person[] adults;
{
    ArrayList minorsList = new ArrayList();
	ArrayList adultsList = new ArrayList();
	for (int i = 0; i < people.length; i++)
		(people[i].age < 18 ? minorsList : adultsList).add(people[i]);
	minors = minorsList.toArray(people);
	adults = adultsList.toArray(people);
}

Java vs Scala

Pattern matching
Infix method call
Function value

val people: Array[Person]
val (minors, adults) = people partition (_.age < 18)

Scala Parallel

Collections .par
parallel version of collection


val people: Array[Person]
val (minors, adults) = people.par partition (_.age < 18)

Sequences .seq
secuencial version of collection

Scala


class Rational(n: Int, d: Int) extends Ordered[Rational] {
  def compare(that: Rational) =
    (this.numer * that.denom) - (that.numer * this.denom)

  require(d != 0)

  private val g = gcd(n.abs, d.abs)
  val numer = n / g
  val denom = d / g

  def this(n: Int) = this(n, 1)

  def + (that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )

  def + (i: Int): Rational =
    new Rational(numer + i * denom, denom)

  def - (that: Rational): Rational =
    new Rational(
      numer * that.denom - that.numer * denom,
      denom * that.denom
    )

  def - (i: Int): Rational =
    new Rational(numer - i * denom, denom)

  def * (that: Rational): Rational =
    new Rational(numer * that.numer, denom * that.denom)

  def * (i: Int): Rational =
    new Rational(numer * i, denom)

  def / (that: Rational): Rational =
    new Rational(numer * that.denom, denom * that.numer)

  def / (i: Int): Rational =
    new Rational(numer, denom * i)

  override def toString = numer +"/"+ denom

  private def gcd(a: Int, b: Int): Int = 
    if (b == 0) a else gcd(b, a % b)

  override def equals(other: Any): Boolean =
    other match {

      case that: Rational =>
        (that canEqual this) &&
        numer == that.numer &&
        denom == that.denom

      case _ => false
    }

  def canEqual(other: Any): Boolean =
    other.isInstanceOf[Rational]

  override def hashCode: Int =
    41 * (
      41 + numer
    ) + denom

}
 

Scala


object Main {
  def main(args: Array[String]) {
    val x = new Rational(2, 3)
    println("x [" + x + "]")
    println("x * x [" + (x * x) + "]")
    println("x * 2 [" + (x * 2) + "]")

    implicit def intToRational(x: Int) = new Rational(x)
    val r = new Rational(2,3)
    println("2 * r [" + (2 * r) + "]")
  }
}

Colecciones

Java 7 Fork Join Framework
Divide el trabajo por el número de Procesadores
Balance de granuralidad del overhead
Cada Thread tiene una Queue que se va ampliando exponencialmente
Mutables
Mayor distribución de carga 

Scala

Easy to use
Concise
Safe
Fast
Scalable

Scala Actors

Sencillos
Muy buena integración con Threads
Son tanto bloqueantes como no bloqueantes

import scala.actors._
object FooActor extends Actor {
 def act(){
  for(i <- 1 to 11){
   doSomething()
   Thread.sleep(1000)
  }
 }
}

Scala Actors



val echoActor = actor {
    while(true) {
        receive {
         case msg => println("Received message " + msg)
        }
    }
}
scala> echoActor ! "My First Message"

AKKA

Middleware basado en actores
Muy buena performance
Ampliamente escalable cluster y clouds
Safety
Akka

Ejemplo Chat

Play Framework
Scala
+
Akka

Clojure

Lenguaje dinámico de propósito general (JVM)
Es un dialecto de LISP
Scripting 
Compila a byte code 
Robusto 

(defn fac-cps [n k]
    (letfn [(cont [v] (k (* v n)))]
		(if (zero? n)
			(k 1)
			(recur (dec n) cont))))

(defn factorial [n]
	(fac-cps n identity))

Java vs Clojure


public class StringUtils {
 public static boolean isBlank(String str) {
  int strLen;
  if (str == null || (strLen = str.length()) == 0) {
   return true;
  }
  for (int i = 0; i < strLen; i++) {
   if ((Character.isWhitespace(str.charAt(i)) == false {
    return false;
   }
  }
  return true;
 }
}

Java vs Clojure



(defn blank? [str] 
    (every #((Character/isWhitespace %) str))



    (defrecord Person [name age])
    
(def foo (->Person "Alex" 34))

Clojure 


(defrecord Message [sender text])
(def messages (ref ()))
(def validate-message-list
  (partial every? #(and (:sender %) (:text %))))
(def messages (ref () :validator validate-message-list))
(defn naive-add-message [msg]
  (dosync (ref-set messages (cons msg @messages))))
(defn add-message [msg]
  (dosync (alter messages conj msg)))
(defn add-message-commute [msg]
  (dosync (commute messages conj msg)))


CLOJURE ASYNC



(ns sample (:require [http.async.client :as http]))

(with-open [client (http/create-client)]
  (let [response (http/GET client "http://neotyk.github.com/http.async.client/")]
    (-> response
      http/await
      http/string)))

Clojure Collections




(map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))

(reduce + (r/map inc [1 2 3])) === (reduce (fn [ret x] (+ ret (inc x))) (+) [1 2 3])

fn * reducible -> reducible

Clojure


LISP mas recargado
Programación Funcional
Dynamic Development (REPL)

Next...

Lenguajes:

Programación Paralela + Universo de Datos

Ejemplo:

Twitter sobrevive a las elecciones de EEUU
31 Millon Tweets 
Tweets per second (TPS)
9.965 TPS -> 8:11pm - 9:11pm
One-second Peek
15.107 TPS -> 8:20 pm

874.560 TPM

Ejemplo:

Twitter migración de Ruby a Java
Real Time Search Engine
Apache Lucene
Java Server Blender
Netty NIO

Ejemplo 2:

Scala
+
Play Framework
+
NoSQL



Gracias a todos...


@antiveroalejo

concurrencia y paralelismo

By aleantivero

concurrencia y paralelismo

  • 238