Clase 13: Colecciones Paralelas¶
Introducción a las Colecciones Paralelas¶
Las colecciones paralelas en Scala permiten ejecutar operaciones sobre colecciones de manera concurrente, aprovechando múltiples núcleos del procesador. Esto mejora el rendimiento en operaciones con grandes volúmenes de datos.
¿Cómo funcionan?¶
Scala divide automáticamente la colección en subconjuntos (particiones) y procesa cada partición en un hilo separado. Luego, combina los resultados parciales para obtener el resultado final.
Convertir una colección secuencial a paralela¶
Para convertir una colección secuencial a paralela, se utiliza el método .par:
val listaSecuencial = List(1, 2, 3, 4, 5)
val listaParalela = listaSecuencial.par
Métodos Principales¶
aggregate¶
El método aggregate es similar a fold, pero permite trabajar en paralelo. Recibe tres parámetros:
- Valor inicial (
zeroValue): Valor desde el cual se comienza la acumulación. - Operación de secuencia (
seqOp): Función que combina el acumulador con cada elemento de la colección. - Operación de combinación (
combOp): Función que combina los resultados parciales de diferentes particiones.
// Sumar las longitudes de las cadenas en un arreglo
Array("a", "ab", "c").aggregate(0)( // Valor inicial: 0
(acc, x) => acc + x.length, // seqOp: suma la longitud de cada elemento al acumulador
(A, B) => A + B // combOp: suma los resultados parciales
)
// Resultado: 4 (1 + 2 + 1)
fold¶
Similar a aggregate, pero requiere que la operación sea asociativa y que el valor inicial sea un elemento neutro (identidad) para la operación.
// Sumar los elementos de un arreglo en paralelo
Array(1, 2, 3, 4, 5).par.fold(0)(_ + _)
// Resultado: 15
reduce¶
Similar a fold, pero no requiere un valor inicial. La colección debe tener al menos un elemento.
// Encontrar el máximo elemento
Array(3, 7, 2, 9, 5).par.reduce((a, b) => if (a > b) a else b)
// Resultado: 9
Consideraciones Importantes¶
Operaciones Asociativas¶
Para que las colecciones paralelas funcionen correctamente, las operaciones deben ser asociativas. Una operación es asociativa si:
\((a \circ b) \circ c = a \circ (b \circ c)\)
Ejemplos de operaciones asociativas: - Suma: \((1 + 2) + 3 = 1 + (2 + 3)\) - Multiplicación: \((2 \times 3) \times 4 = 2 \times (3 \times 4)\) - Máximo: \(max(max(1,2),3) = max(1,max(2,3))\)
Operaciones No Asociativas¶
La resta no es asociativa: - \((5 - 3) - 2 = 0\) - \(5 - (3 - 2) = 4\)
Hilos y Paralelismo¶
Scala utiliza un pool de hilos (ForkJoinPool) para ejecutar las operaciones paralelas. El número de hilos disponibles depende del número de núcleos del procesador.
// Verificar el número de hilos disponibles
println(Runtime.getRuntime.availableProcessors())
Ejemplo Completo¶
// Calcular la suma de cuadrados en paralelo
val numeros = (1 to 1000000).toArray.par
val sumaCuadrados = numeros.aggregate(0)( // Valor inicial: 0
(acc, x) => acc + (x * x), // seqOp: suma el cuadrado de cada elemento
(acc1, acc2) => acc1 + acc2 // combOp: combina resultados parciales
)
println(s"Suma de cuadrados: $sumaCuadrados")
Tabla Resumen¶
| Concepto | Descripción | Ejemplo |
|---|---|---|
.par |
Convierte una colección secuencial a paralela | lista.par |
aggregate |
Acumula valores con valor inicial, operación de secuencia y combinación | coleccion.aggregate(0)(_+_, _+_) |
fold |
Similar a aggregate pero requiere operación asociativa | coleccion.par.fold(0)(_+_) |
reduce |
Similar a fold pero sin valor inicial | coleccion.par.reduce(_+_) |
| Asociatividad | Propiedad necesaria para operaciones paralelas | (a+b)+c = a+(b+c) |
| ForkJoinPool | Pool de hilos usado por Scala para paralelismo | Configuración automática |
Comentarios adicionales: - Las colecciones paralelas son ideales para operaciones intensivas en CPU con grandes conjuntos de datos. - No todas las operaciones se benefician del paralelismo; para colecciones pequeñas, la sobrecarga de crear hilos puede ser mayor que la ganancia. - Es importante asegurar que las operaciones sean sin efectos secundarios (inmutables) para evitar condiciones de carrera. - El orden de los resultados no está garantizado en operaciones paralelas.