Programación concurrente con GPars

49
Programación concurrente con Groovy Wednesday, May 30, 12

description

GPars talk at @MadridGUG 05/2012

Transcript of Programación concurrente con GPars

Page 1: Programación concurrente con GPars

Programación concurrente con Groovy

Wednesday, May 30, 12

Page 2: Programación concurrente con GPars

Hola!Mario García (@marioggar)

Freelance Software alchemist

Groovy passionate!

Madrid Groovy User Group member (@MadridGUG)

Wednesday, May 30, 12

Page 3: Programación concurrente con GPars

¿Qué es GPars?Es un framework que proporciona a los desarrolladores Java una forma segura e intuitiva de manejar tareas concurrentes

Escrito en su mayoría en Java

Sospechosos habituales:

Vaclav Pech (Jetbrains)

Wednesday, May 30, 12

Page 4: Programación concurrente con GPars

¿Por qué usar GPars?Usas Groovy o Java

Quieres escribir código empleando concurrencia ó paralelismo

Vas a usar hardware de varios nucleos

La programación concurrente siempre te ha parecido muy compleja.

PORQUE ESTA INCLUIDO EN GROOVY

Wednesday, May 30, 12

Page 5: Programación concurrente con GPars

¿Qué vamos a ver?Ayudas a nivel de código

Conceptos a nivel de arquitectura

Protección de objetos compartidos

Wednesday, May 30, 12

Page 6: Programación concurrente con GPars

Ayudas a nivel de código

Wednesday, May 30, 12

Page 7: Programación concurrente con GPars

Ayudas a nivel de códigoEstas ayudas nos permitirán escribir código concurrente variando poco o nada nuestro código actual.

Parallel Arrays (fork/join)

Syntaxis mas funcional (map/reduce/filter)

Ejecución asincrona de funciones (closures)

Wednesday, May 30, 12

Page 8: Programación concurrente con GPars

Parallel Arrays

Wednesday, May 30, 12

Page 9: Programación concurrente con GPars

Parallel Arrays Todos los métodos que utilizabamos sobre colecciones tienen ahora a su “hermano paralelo”.

findAll --> findAllParallel, collect--> collectParallel

Estos métodos nos permiten realizar las mismas tareas de manera parallela cordinandolas a la finalizacion de la misma.

Basado en Fork/Join jsr166

Wednesday, May 30, 12

Page 10: Programación concurrente con GPars

def findAllPeopleNameOver30AndSingle(people){people.

findAll{it.age >30}.collect{it.name}

}

Wednesday, May 30, 12

Page 11: Programación concurrente con GPars

def findAllPeopleNameOver30AndSingle(people){ GParsPool.withPool {

people.findAllParallel{it.age >30}.collectParallel{it.name}

}}

Wednesday, May 30, 12

Page 12: Programación concurrente con GPars

Ayudas a nivel de códigoGParsPool.withPool

La clase GParsPool es la que permite el DSL de concurrencia para collecciones y objetos

groovyx.gpars.GParsPool

El método withPool puede tomar como parametros el numero de hilos creados en el pool y un manejador de excepciones

Wednesday, May 30, 12

Page 13: Programación concurrente con GPars

Parallel ArraysMeta-class enchancer

Si no queremos “encerrar” nuestro código con withPool{ ... } podemos utilizar la clase ParallelEnhancer

groovyx.gpars.ParallelEnhancer

Agregara al metaClass de nuestra coleccion las nuevas funciones concurrentes.

Wednesday, May 30, 12

Page 14: Programación concurrente con GPars

def findAllPeopleNameOver30AndSingle(people){ParallelEnhancer.enhanceInstance(people)people.

findAllParallel{it.age > 30}.collectParallel{it.name}

}

Wednesday, May 30, 12

Page 15: Programación concurrente con GPars

Parallel ArraysUmm no podría hacerlo con menos?

Claro!! :)

Podemos seguir utilizando la misma sintaxis de colecciones bien utilizando el método makeConcurrent() sobre una colección...

Wednesday, May 30, 12

Page 16: Programación concurrente con GPars

def findAllPeopleNameOver30AndSingle(people){ParallelEnhancer.enhanceInstance(people)people.makeConcurrent().

findAll{it.age > 30}.collect{it.name}

}

Wednesday, May 30, 12

Page 17: Programación concurrente con GPars

Parallel Arrays...Bien manteniendo nuestro método original e invocandole pasandole como parametro una colección concurrente.

Wednesday, May 30, 12

Page 18: Programación concurrente con GPars

def findAllPeopleNameOver30AndSingle(people){people.

findAll{it.age > 30}.collect{it.name}

}

ParallelEnhancer.enhanceInstance(people)findAllPeopleNameOver30AndSingle(

people.makeConcurrent())

Wednesday, May 30, 12

Page 19: Programación concurrente con GPars

Parallel ArraysUn gatito muere en algun lugar cuando:

Se accede a una colección not-thread-safe desde un método “parallel”

Se crea una closure con estado. Todas las closures que se pasan como parametro a un método paralelo deben de ser thread-safe o dicho de otro modo deben ser “sin estado”

Wednesday, May 30, 12

Page 20: Programación concurrente con GPars

Parallel Arrays

def findAllPeopleNameOver30AndSingle(people){def result = []ParallelEnhancer.enhanceInstance(people)people.

findAllParallel{it.age > 30}.eachParallel{ result << it.name}

result}

Miaoooouuuu

Wednesday, May 30, 12

Page 21: Programación concurrente con GPars

Map/Reduce

Wednesday, May 30, 12

Page 22: Programación concurrente con GPars

Map/ReduceLa DSL Map/Reduce para el manejo de colecciones da a GPars un sabor más “funcional”.

Map/Reduce “rinde más rápido” que los métodos xxxParallel para operaciones encadenadas sobre una coleccion paralela

Algunos métodos map/reduce se pueden usar de la misma manera que los metodos xxxParallel ya que tienen semanticas parecidas

Wednesday, May 30, 12

Page 23: Programación concurrente con GPars

Map/Reducedef findAllPeopleNameOver30AndSingle(people){

ParallelEnhancer.enhanceInstance(people)people.parallel.

filter{it.age > 30}.map{it.name}.collection

}

Wednesday, May 30, 12

Page 24: Programación concurrente con GPars

Map/ReduceCada ejecución xxxParallel hace la conversión paralela-->normal para cumplir con el contrato de los métodos no paralelos.

Los métodos Map/Reduce se ejecutan sobre una la colección paralela. Usamos la propiedad parallel para acceder a ella.

Los métodos Map/Reduce devuelven una colección paralela. Cuando queramos que devuelvan una colección normal utilizamos la propiedad collection

Wednesday, May 30, 12

Page 25: Programación concurrente con GPars

soccerDays.parallel.filter{it.fieldViewers > 1000000}.map{[it,(it.soccerPlayers / it.fieldViewers) * 100]}.filter{it[1] > 0.018}.map{it[0].day}.collection

Map/Reduce

Wednesday, May 30, 12

Page 26: Programación concurrente con GPars

Ejecución asincronaCombinar la ejecución asincrona de varias tareas y pasarlas como argumentos a otras funciones

Hay tareas que se pueden descomponer en varias subtareas más sencillas

Mientras que habrá subtareas que tarden en ejecutarse, puede que otras solo tarden un momento

Si ejecutaramos secuencialmente las tareas, las pesadas bloquearian a las ligeras.

Wednesday, May 30, 12

Page 27: Programación concurrente con GPars

Ejecución asincronaEjemplo: Media Aritmetica

Composición de closures:Hay que dividir la computación del problema en diferentes closures

La ejecución de cada closure por separado es inmutable, no depende de los datos de la otra

Se combinaran en una tercera closure que cordinará los resultados de ambas

Wednesday, May 30, 12

Page 28: Programación concurrente con GPars

Ejecución asincronadef peopleYears = {people-> people*.age.sum()}.asyncFun()def howManyPeople = {people-> people.size()}.asyncFun()def avg = {yearsSum,peopleSize->

yearsSum/peopleSize}.asyncFun()

avg(peopleYears(people),howManyPeople(people)

)

Wednesday, May 30, 12

Page 29: Programación concurrente con GPars

Conceptos a nivel de arquitectura

Wednesday, May 30, 12

Page 30: Programación concurrente con GPars

Concetos a nivel...En esta parte veremos partes de GPars más avanzadas que requieren que planteemos nuestra aplicación de otra manera

Dataflow

Actores

Wednesday, May 30, 12

Page 31: Programación concurrente con GPars

DataflowGPars nos permite definir procesos como un flujo de datos en lugar de como un flujo de ejecución

Se genera un arbol de dependencias entre datos

Wednesday, May 30, 12

Page 32: Programación concurrente con GPars

Dataflow

Upps...

Wednesday, May 30, 12

Page 33: Programación concurrente con GPars

Dataflow

rows

statestop

result

Esto esta mejor...

Wednesday, May 30, 12

Page 34: Programación concurrente con GPars

DataflowDemo: Tornados en Estados Unidos

Recuperamos todos los ocurridos (rows)

Recuperamos el maestro de estados (states)

Recogemos los 3 más peligrosos (result)

Recogemos los nombres (result)

Contabilizamos fecha de finalización (end)

Wednesday, May 30, 12

Page 35: Programación concurrente con GPars

Dataflowdef flow = new Dataflows()task {

flow.rows = getTornadoRows() flow.remoteData = getSimulatedDataFromARemoteHost()

}task {flow.states = getStateRows()}task {flow.top = ... }task {

flow.result = flow.top.collect{data->flow.states.find{s-> s.stateCode == data.stateCode}.stateName

}flow.end = System.currentTimeMillis()

}

1)

2)3)

4)

Wednesday, May 30, 12

Page 36: Programación concurrente con GPars

DataflowFlow:

1) Se descargan los datos de los tornados y unos datos remotos (Estos ultimos hacen esperar un poco el proceso)

2) Esta tarea como no tiene ninguna dependencia se ejecuta a la vez que la tarea uno evitando la espera del proceso remoto

3) Se ejecuta cuando se han resuelto las variables de la tarea 1

4) Se ejecuta cuando se han resuelto las variables de las tareas 2 y 3 (flow.top y flow.states)

Wednesday, May 30, 12

Page 37: Programación concurrente con GPars

DataflowSolución bastante elegante estableciendo dependencias entre datos

Cuidado con las dependencias circulares == deadlock

No lo recomiendo para arboles “muy grandes”. Se pierde el objetivo y se puede acabar en el punto anterior.

Wednesday, May 30, 12

Page 38: Programación concurrente con GPars

Actors

Wednesday, May 30, 12

Page 39: Programación concurrente con GPars

Actors

NO ESTOS NO

Wednesday, May 30, 12

Page 40: Programación concurrente con GPars

ActorsLos actores nos permiten la cordinación explicita entre procesos asincronos.

Recomendado para tareas complejas con dependencias de paso de mensajes entre ambas.

Simula el paradigma de envio de mensajes (send,reply)

Wednesday, May 30, 12

Page 41: Programación concurrente con GPars

ActorsInspirado en los Actores de Scala pero mejorado.

Actores con estado: Solo en casos concretos

Actores sin estado: recomendados

Wednesday, May 30, 12

Page 42: Programación concurrente con GPars

ActorsDemo: F1

Tenemos una serie de corredores cuyos coches tienen que notificar a direccion de carrera su posición.

Actores implicados

Conductores: Notifican su posición

Comisario de carrera: Notifica el estado de la carrera

Wednesday, May 30, 12

Page 43: Programación concurrente con GPars

¿Para qué podemos usarlo?

Wednesday, May 30, 12

Page 44: Programación concurrente con GPars

¿Para qué?Ideal para:

Procesos de calculo matemático

Procesos en arbol con nodos inmutables pero dependientes como por ejemplo:

Ejemplo: Media aritmetica. La suma de elementos me la da un servicio que tarda x, pero mientras espero puedo calcular el numero total de elementos.

En general procesos en los que tienes que componer datos dependiendo de otros que provinenen de diferentes fuentes heterogeneas y con alta latencia.

Wednesday, May 30, 12

Page 45: Programación concurrente con GPars

¿Para qué?Ideal para:

Programación funcional (Map/Reduce)

Programación orientada a eventos (Actores)

Wednesday, May 30, 12

Page 46: Programación concurrente con GPars

GPars es mucho másAgents

Speculations

STM (Software Transactional Memory)

...

Wednesday, May 30, 12

Page 47: Programación concurrente con GPars

GPars es mucho másPágina proyecto

http://gpars.codehaus.org/

Libros

Groovy In Action (2nd Ed) (Contiene un capítulo dedicado unicamente a GPars)

Wednesday, May 30, 12

Page 48: Programación concurrente con GPars

GPars es mucho másBlogs, videos...

Paul King (Video) GPars Concurrency

http://www.youtube.com/watch?v=dUDKnIIWw48

Tomas Lin: Grails/Gorm con GPars

http://fbflex.wordpress.com/2010/06/11/writing-batch-import-scripts-with-grails-gsql-and-gpars/

Arturo Herrero (Slide) Functional Groovy

http://www.slideshare.net/arturoherrero/functional-programming-with-groovy

Wednesday, May 30, 12

Page 49: Programación concurrente con GPars

Q & A

Wednesday, May 30, 12