El paral·lelisme és una tècnica que permet executar múltiples càlculs simultàniament, aprofitant els recursos de maquinari disponibles, com ara múltiples nuclis de CPU. En Haskell, el paral·lelisme es pot aconseguir de diverses maneres, utilitzant biblioteques i funcions específiques. Aquest tema cobrirà els conceptes bàsics del paral·lelisme en Haskell, incloent-hi exemples pràctics i exercicis per ajudar-te a comprendre com implementar paral·lelisme en els teus programes.

Conceptes Clau

  1. Paral·lelisme vs Concurrència:

    • Paral·lelisme: Executar múltiples càlculs simultàniament per reduir el temps total d'execució.
    • Concurrència: Gestionar múltiples tasques alhora, però no necessàriament executant-les simultàniament.
  2. Eines per al Paral·lelisme en Haskell:

    • par i pseq
    • Estratègies de paral·lelisme (Control.Parallel.Strategies)
    • async i await (Control.Concurrent.Async)

Exemples Pràctics

Exemple 1: Utilitzant par i pseq

El mòdul Control.Parallel proporciona les primitives par i pseq per indicar al compilador que certs càlculs es poden realitzar en paral·lel.

import Control.Parallel (par, pseq)

-- Funció per calcular la suma de quadrats de dos llistes en paral·lel
sumOfSquares :: [Int] -> [Int] -> Int
sumOfSquares xs ys = 
    let sumX = sum (map (^2) xs)
        sumY = sum (map (^2) ys)
    in sumX `par` (sumY `pseq` (sumX + sumY))

main :: IO ()
main = print $ sumOfSquares [1..1000000] [1..1000000]

Explicació:

  • par indica que sumX es pot calcular en paral·lel amb el càlcul de sumY.
  • pseq assegura que sumY es calcula abans de combinar els resultats.

Exemple 2: Utilitzant Estratègies de Paral·lelisme

El mòdul Control.Parallel.Strategies proporciona una manera més estructurada de definir com es poden paral·lelitzar els càlculs.

import Control.Parallel.Strategies (parList, rseq, using)

-- Funció per calcular la suma de quadrats de una llista en paral·lel
sumOfSquares :: [Int] -> Int
sumOfSquares xs = sum (map (^2) xs `using` parList rseq)

main :: IO ()
main = print $ sumOfSquares [1..1000000]

Explicació:

  • parList rseq aplica l'estratègia de paral·lelisme a cada element de la llista.
  • using aplica l'estratègia especificada a la llista.

Exemple 3: Utilitzant async i await

El mòdul Control.Concurrent.Async permet crear tasques asíncrones que es poden esperar posteriorment.

import Control.Concurrent.Async (async, wait)

-- Funció per calcular la suma de quadrats de dos llistes en paral·lel
sumOfSquares :: [Int] -> [Int] -> IO Int
sumOfSquares xs ys = do
    a1 <- async $ return $ sum (map (^2) xs)
    a2 <- async $ return $ sum (map (^2) ys)
    sumX <- wait a1
    sumY <- wait a2
    return (sumX + sumY)

main :: IO ()
main = do
    result <- sumOfSquares [1..1000000] [1..1000000]
    print result

Explicació:

  • async crea una tasca asíncrona.
  • wait espera que la tasca asíncrona es completi i retorna el resultat.

Exercicis Pràctics

Exercici 1: Paral·lelitzar el Càlcul de Factorials

Escriu una funció que calculi el factorial de dos nombres en paral·lel utilitzant par i pseq.

import Control.Parallel (par, pseq)

factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)

factorialParallel :: Int -> Int -> Int
factorialParallel x y = 
    let factX = factorial x
        factY = factorial y
    in factX `par` (factY `pseq` (factX + factY))

main :: IO ()
main = print $ factorialParallel 10 20

Exercici 2: Utilitzant Estratègies de Paral·lelisme

Escriu una funció que calculi la suma de cubs d'una llista en paral·lel utilitzant parList i rseq.

import Control.Parallel.Strategies (parList, rseq, using)

sumOfCubes :: [Int] -> Int
sumOfCubes xs = sum (map (^3) xs `using` parList rseq)

main :: IO ()
main = print $ sumOfCubes [1..1000000]

Resum

En aquesta secció, hem après els conceptes bàsics del paral·lelisme en Haskell i hem vist com utilitzar par i pseq, estratègies de paral·lelisme, i async i await per paral·lelitzar càlculs. Els exercicis pràctics proporcionats t'ajudaran a consolidar aquests conceptes i a aplicar-los en els teus propis programes. En la següent secció, explorarem la concurrència en Haskell, que és una tècnica relacionada però diferent del paral·lelisme.

© Copyright 2024. Tots els drets reservats