Sunteți pe pagina 1din 17

Calcul Paralel în Haskell

7 ianuarie 2010
Mihai Maruseac
2
Sumar

• Paralelism și Haskell
o De ce paralelism?
o De ce Haskell? De ce nu Haskell?
• Construcții specifice
o Threads. MVars,. Chans
o seq, par
• Communicating Haskell Processes

3
Paralelism (1)

• Nu ar fi frumos dacă prin simplul upgrade al calculatorului nostru


(sau orice alt sistem de calcul) de la 1 procesor la 2 programele ar
lucra de două ori mai rapid?
• Dublare procesoare == înjumătățire timp calcul?
• NU
• Mod secvențial de programare. De ce?
• Programele abundă de paralelism (dintr-un anumit punct de
vedere)
• Problemă: noi scriem cod secvențial

4
Paralelism (2)

• Paralelismul inițial – obturat sau eliminat


• Orientare spre paralelism
o Adnotări – hinturi pentru compilator (OpenMP)
o Extindere limbaj cu construcții explicite (threads, MPI)
• Paralelizare automată
• Este tot ce putem face?
• Paralelism implicit in limbaj (Haskell)

5
Pro Haskell

• Fără destructive updates -> many reads, one write


• Fără dependențe între variabile
• Evaluare leneșă -> multiple funcții în paralel
• Construcții specifice usor de folosit
• Transformare spre paralelism facilă
• Mulți algoritmi nu au stări. Programarea funcțională nu are stări
• Similar paradigmei dataflow-programming

6
Contra Haskell

• Cât de ușor putem exprima orice algoritm fara a folosi conceptul de


stare?
• Unele probleme – practic imposibil de exprimat în stil funcțional
• Probleme cu reprezentare imperativă mai facilă
• Copieri nenecesare
• Garbage collection
• Sincronizare (s-a terminat calculul f?)
• Monade și FRP

7
Threads (1)

• Problema: vrem să calculam factorialul unui număr natural și


produsul numerelor impare mai mici decăt el
• Cazul secvential: pierdem mult timp în IO și înmulțire (demo)
• Folosim un thread pentru calcul
• forkIO :: IO () -> IO ThreadId
• Programul se termină acum în timp constant (demo)

8
Threads (2)

• Thread-urile sunt minimaliste și nondeterministe


• Main Thread /= forked thread (terminare)
• Comunicarea între ele trebuie scrisă de programator
• MVar (sincronizare, excludere mutuală, notificări)
• putMVar :: MVar a -> a -> IO()
• takeMVar :: MVar a -> IO a
• Deadlocks, exceptions
• modifyMVar :: Mvar a -> (a -> IO (a, b)) -> IO b

9
Threads (3)

• Chan -> canal unidirecțional


• Util dacă este nevoie de un singur tip de mesaje
• Unbounded
• readChan, writeChan

• MVar și Chan nu sunt stricte -> program paralel?

• Nu avem mult paralelism (nu lucrăm optim)

10
Operatorii seq si par (1)

• Luăm funcția de calcul a factorialului: fact n = product *1..n+

• O putem scrie ca: fact n = product [1..n/2] * product [n/2+1..n]

• par :: a -> b -> b

• Evalueaza în paralel primul și al doilea argument, returnându-l pe ultimul

• seq, pseq: evaluează primul argument înainte de a-l întoarce pe al doilea

• De ce 2 funcții?

11
Operatorii seq si par (2)
import Control.Parallel
import System.Environment (getArgs)

prod min max = p1 `par` (p2 `pseq` p1 * p2)


where
mid = (min + max) `div` 2
p1 = prod min mid
p2 = prod (mid+1) max
• Codul devine:
fact n = prod 1 n
prod2 n = (prod . filter even) [1..n]

main = do
args <- getArgs
let n = read $ head args
putStrLn $ show $ fact n
putStrLn $ show $ prod2 n

12
Communicating Haskell Processes

• Model inspirat din Communicating sequential processes (Hoare)

• 4 operatori: <-> (choice); <||> (parallel), >> (sequence), forever

• Monadă proprie (CHP)

• Operatii proprii: readChannel, writeChannel

• Canalele sincrone

• Implementare foarte apropiată de MPI

13
CHP – terminarea algoritmilor

• Noțiunea de poison: când un proces se termină el injectează otravă pe toate


canalele sale

• Un proces ce primește otravă se va termina prin același algoritm

14
CHP – Exemplu

• Generare numere prime – expanding pipeline

filterDiv :: Integer -> Chanin Integer -> Chanout Integer -> CHP ()
filterDiv n input output = forever $ do
x <- readChannel input
when (x `mod` n /= 0) $ writeChannel output x
end :: Chanin Integer -> Chanout Integer -> CHP ()
end input output = do
x <- readChannel input
writeChannel output x
(filterDiv x |->| end) input output
genStream :: Chanout Integer -> CHP ()
genStream output = mapM_ (writeChannel output) [2..]

primes :: Chanout Integer -> CHP ()


primes = genStream ->| end

15
Bibliografie

• http://www.embedded.com/design/multicore/201500267

• http://www.embedded.com/design/multicore/201804960

• http://www.embedded.com/design/multicore/201806715

• http://chplib.wordpress.com/

• http://book.realworldhaskell.org/read/

16
The End

?
07.01.09 17

S-ar putea să vă placă și