Haskell Language
Parallelität
Suche…
Parameter
Typ / Funktion | Detail |
---|---|
data Eval a | Eval ist eine Monade, die die Definition paralleler Strategien erleichtert |
type Strategy a = a -> Eval a | eine Funktion, die eine parallele Evaluierungsstrategie verkörpert. Die Funktion durchläuft (Teile von) ihr Argument und wertet Teilausdrücke parallel oder nacheinander aus |
rpar :: Strategy a | spornt sein Argument (zur parallelen Auswertung) |
rseq :: Strategy a | wertet sein Argument zu einer schwachen Kopfnormalform aus |
force :: NFData a => a -> a | wertet die gesamte Struktur des Arguments aus und reduziert es auf Normalform, bevor das Argument selbst zurückgegeben wird. Sie wird vom Control.DeepSeq-Modul bereitgestellt |
Bemerkungen
Simon Marlows Buch Concurrent and Parallel Programming in Haskell ist hervorragend und deckt eine Vielzahl von Konzepten ab. Es ist auch für den neuesten Haskell-Programmierer sehr gut zugänglich. Es wird dringend empfohlen und ist kostenlos als PDF oder Online verfügbar.
Parallel gegen gleichzeitig
Simon Marlow sagt es am besten :
Ein Parallelprogramm ist eines, das eine Vielzahl von Computerhardware (z. B. mehrere Prozessorkerne) verwendet, um eine Berechnung schneller durchzuführen. Das Ziel besteht darin, zu einer früheren Antwort zu gelangen, indem verschiedene Teile der Berechnung an verschiedene Prozessoren delegiert werden, die gleichzeitig ausgeführt werden.
Im Gegensatz dazu ist Parallelität eine Programmstrukturierungsmethode, bei der es mehrere Kontrollthreads gibt. Konzeptionell werden die Kontroll-Threads „gleichzeitig“ ausgeführt. das heißt, der Benutzer sieht, dass seine Effekte verschachtelt sind. Ob sie gleichzeitig ausgeführt werden oder nicht, ist ein Implementierungsdetail. Ein gleichzeitiges Programm kann auf einem einzigen Prozessor durch verschachtelte Ausführung oder auf mehreren physischen Prozessoren ausgeführt werden.
Schwache Kopfnormalform
Es ist wichtig zu wissen, wie Lazy-Evaluation funktioniert. Der erste Abschnitt dieses Kapitels wird eine starke Einführung in WHNF und dessen Beziehung zur parallelen und gleichzeitigen Programmierung geben.
Die Eval Monad
Parallelität in Haskell kann mit der Eval
Monad von Control.Parallel.Strategies
ausgedrückt werden, wobei rseq
Funktionen rpar
und rseq
werden.
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)
Das Ausführen von main
oben wird sofort ausgeführt und "return", während die beiden Werte a
und b
im Hintergrund durch rpar
.
Hinweis: -threaded
Sie sicher, dass Sie mit -threaded
kompilieren, -threaded
parallel ausgeführt werden kann.
rpar
rpar :: Strategy a
führt die angegebene Strategie aus (Rückruf: type Strategy a = a -> Eval a
) parallel:
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..])
Wenn Sie dies ausführen, wird das gleichzeitige Verhalten veranschaulicht:
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
Wir können rseq :: Strategy a
, um ein Argument in die Normalform von Weak Head zu erzwingen:
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)
Dies ändert die Semantik des rpar
Beispiels auf subtile rpar
. Während Letzteres sofort zurückkehrt, während die Werte im Hintergrund berechnet werden, wartet dieses Beispiel, bis a
für WHNF ausgewertet werden kann.