Haskell Language
Parallelism
Zoeken…
parameters
Type / Functie | Detail |
---|---|
data Eval a | Eval is een monade die het gemakkelijker maakt om parallelle strategieën te definiëren |
type Strategy a = a -> Eval a | een functie die een parallelle evaluatiestrategie belichaamt. De functie doorloopt (delen van) zijn argument, en evalueert subexpressies parallel of in volgorde |
rpar :: Strategy a | vonkt zijn argument (voor parallelle evaluatie) |
rseq :: Strategy a | evalueert zijn argument voor de normale vorm van een zwak hoofd |
force :: NFData a => a -> a | evalueert de hele structuur van zijn argument, reduceert het tot de normale vorm, voordat het argument zelf wordt teruggestuurd. Het wordt geleverd door de module Control.DeepSeq |
Opmerkingen
Het boek van Simon Marlow , Concurrent and Parallel Programming in Haskell, is uitstekend en omvat een groot aantal concepten. Het is ook zeer toegankelijk voor zelfs de nieuwste Haskell-programmeur. Het wordt sterk aanbevolen en is gratis beschikbaar in PDF of online.
Parallel versus gelijktijdig
Simon Marlow zegt het beste :
Een parallel programma is een programma dat een veelvoud van computerhardware (bijv. Meerdere processorcores) gebruikt om een berekening sneller uit te voeren. Het doel is om eerder tot het antwoord te komen, door verschillende delen van de berekening te delegeren aan verschillende processoren die tegelijkertijd worden uitgevoerd.
Concurrency is daarentegen een programmastructureringstechniek waarbij er meerdere controledraden zijn. Conceptueel worden de draden van controle "tegelijkertijd" uitgevoerd; dat wil zeggen, de gebruiker ziet hun effecten verweven. Of ze daadwerkelijk tegelijkertijd uitvoeren of niet is een implementatiedetail; een gelijktijdig programma kan worden uitgevoerd op een enkele processor via interleaved uitvoering of op meerdere fysieke processors.
Zwak hoofd Normale vorm
Het is belangrijk om te weten hoe luie evaluatie werkt. Het eerste deel van dit hoofdstuk geeft een sterke introductie in WHNF en hoe dit verband houdt met parallelle en gelijktijdige programmering.
De Eval Monad
Parallellisme in Haskell kan worden uitgedrukt met behulp van de Eval
Monad van Control.Parallel.Strategies
, met behulp van de functies rpar
en rseq
(onder andere).
f1 :: [Int]
f1 = [1..100000000]
f2 :: [Int]
f2 = [1..200000000]
main = runEval $ do
a <- rpar (f1) -- this'll take a while...
b <- rpar (f2) -- this'll take a while and then some...
return (a,b)
main
uitvoeren hierboven wordt onmiddellijk uitgevoerd en "geretourneerd", terwijl de twee waarden a
en b
op de achtergrond worden berekend via rpar
.
Opmerking: zorg ervoor dat u compileert met -threaded
voor parallelle uitvoering.
RPAR
rpar :: Strategy a
voert de gegeven strategie (terugroepen: type Strategy a = a -> Eval a
) parallel uit:
import Control.Concurrent
import Control.DeepSeq
import Control.Parallel.Strategies
import Data.List.Ordered
main = loop
where
loop = do
putStrLn "Enter a number"
n <- getLine
let lim = read n :: Int
hf = quot lim 2
result = runEval $ do
-- we split the computation in half, so we can concurrently calculate primes
as <- rpar (force (primesBtwn 2 hf))
bs <- rpar (force (primesBtwn (hf + 1) lim))
return (as ++ bs)
forkIO $ putStrLn ("\nPrimes are: " ++ (show result) ++ " for " ++ n ++ "\n")
loop
-- Compute primes between two integers
-- Deliberately inefficient for demonstration purposes
primesBtwn n m = eratos [n..m]
where
eratos [] = []
eratos (p:xs) = p : eratos (xs `minus` [p, p+p..])
Als u dit uitvoert, wordt het gelijktijdige gedrag aangetoond:
Enter a number
12
Enter a number
Primes are: [2,3,5,7,8,9,10,11,12] for 12
100
Enter a number
Primes are: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100] for 100
200000000
Enter a number
-- waiting for 200000000
200
Enter a number
Primes are: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200] for 200
-- still waiting for 200000000
rseq
We kunnen rseq :: Strategy a
gebruiken om een argument te forceren om de normale vorm van het hoofd te rseq :: Strategy a
:
f1 :: [Int]
f1 = [1..100000000]
f2 :: [Int]
f2 = [1..200000000]
main = runEval $ do
a <- rpar (f1) -- this'll take a while...
b <- rpar (f2) -- this'll take a while and then some...
rseq a
return (a,b)
Dit verandert subtiel de semantiek van het rpar
voorbeeld; terwijl deze laatste onmiddellijk zou terugkeren terwijl de waarden op de achtergrond worden berekend, wacht dit voorbeeld tot a
kan worden geëvalueerd naar WHNF.