Post on 26-May-2015
description
transcript
Programación concurrente con Groovy
Wednesday, May 30, 12
Hola!Mario García (@marioggar)
Freelance Software alchemist
Groovy passionate!
Madrid Groovy User Group member (@MadridGUG)
Wednesday, May 30, 12
¿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
¿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
¿Qué vamos a ver?Ayudas a nivel de código
Conceptos a nivel de arquitectura
Protección de objetos compartidos
Wednesday, May 30, 12
Ayudas a nivel de código
Wednesday, May 30, 12
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
Parallel Arrays
Wednesday, May 30, 12
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
def findAllPeopleNameOver30AndSingle(people){people.
findAll{it.age >30}.collect{it.name}
}
Wednesday, May 30, 12
def findAllPeopleNameOver30AndSingle(people){ GParsPool.withPool {
people.findAllParallel{it.age >30}.collectParallel{it.name}
}}
Wednesday, May 30, 12
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
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
def findAllPeopleNameOver30AndSingle(people){ParallelEnhancer.enhanceInstance(people)people.
findAllParallel{it.age > 30}.collectParallel{it.name}
}
Wednesday, May 30, 12
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
def findAllPeopleNameOver30AndSingle(people){ParallelEnhancer.enhanceInstance(people)people.makeConcurrent().
findAll{it.age > 30}.collect{it.name}
}
Wednesday, May 30, 12
Parallel Arrays...Bien manteniendo nuestro método original e invocandole pasandole como parametro una colección concurrente.
Wednesday, May 30, 12
def findAllPeopleNameOver30AndSingle(people){people.
findAll{it.age > 30}.collect{it.name}
}
ParallelEnhancer.enhanceInstance(people)findAllPeopleNameOver30AndSingle(
people.makeConcurrent())
Wednesday, May 30, 12
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
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
Map/Reduce
Wednesday, May 30, 12
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
Map/Reducedef findAllPeopleNameOver30AndSingle(people){
ParallelEnhancer.enhanceInstance(people)people.parallel.
filter{it.age > 30}.map{it.name}.collection
}
Wednesday, May 30, 12
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
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
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
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
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
Conceptos a nivel de arquitectura
Wednesday, May 30, 12
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
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
Dataflow
Upps...
Wednesday, May 30, 12
Dataflow
rows
statestop
result
Esto esta mejor...
Wednesday, May 30, 12
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
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
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
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
Actors
Wednesday, May 30, 12
Actors
NO ESTOS NO
Wednesday, May 30, 12
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
ActorsInspirado en los Actores de Scala pero mejorado.
Actores con estado: Solo en casos concretos
Actores sin estado: recomendados
Wednesday, May 30, 12
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
¿Para qué podemos usarlo?
Wednesday, May 30, 12
¿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
¿Para qué?Ideal para:
Programación funcional (Map/Reduce)
Programación orientada a eventos (Actores)
Wednesday, May 30, 12
GPars es mucho másAgents
Speculations
STM (Software Transactional Memory)
...
Wednesday, May 30, 12
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
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
Q & A
Wednesday, May 30, 12