Parallel ¡Func+onal ¡Programming ¡ Lecture ¡2 ¡
Mary ¡Sheeran ¡
(with ¡thanks ¡to ¡Simon ¡Marlow ¡for ¡use ¡of ¡slides) ¡
¡ ¡ ¡
h>p://www.cse.chalmers.se/edu/course/pfp ¡
Parallel Func+onal Programming Lecture 2 Mary Sheeran - - PowerPoint PPT Presentation
Parallel Func+onal Programming Lecture 2 Mary Sheeran (with thanks to Simon Marlow for use of slides) h>p://www.cse.chalmers.se/edu/course/pfp Remember
Mary ¡Sheeran ¡
(with ¡thanks ¡to ¡Simon ¡Marlow ¡for ¡use ¡of ¡slides) ¡
¡ ¡ ¡
h>p://www.cse.chalmers.se/edu/course/pfp ¡
calls ¡made—and ¡makes ¡a ¡very ¡large ¡number! ¡
nfib :: Integer -> Integer nfib n | n<2 = 1 nfib n = nfib (n-1) + nfib (n-2) + 1
n ¡ nfib ¡n ¡ 10 ¡ 177 ¡ 20 ¡ 21891 ¡ 25 ¡ 242785 ¡ 30 ¡ 2692537 ¡
nfib ¡40 ¡
¡
– (and ¡return ¡y) ¡
a ¡parallel ¡task—or ¡it ¡may ¡not ¡
¡
¡
¡
import Control.Parallel rfib :: Integer -> Integer rfib n | n < 2 = 1 rfib n = nf1 `par` nf2 `pseq` nf2 + nf1 + 1 where nf1 = rfib (n-1) nf2 = rfib (n-2)
before ¡…) ¡
import Control.Parallel rfib :: Integer -> Integer rfib n | n < 2 = 1 rfib n = nf1 `par` (nf2 `pseq` nf2 + nf1 + 1) where nf1 = rfib (n-1) nf2 = rfib (n-2)
$ ¡./NF ¡ ¡+RTS ¡ ¡-‑N4 ¡ ¡-‑s ¡ ¡
331160281 ¡ ¡ ¡ ¡ ¡ ¡… ¡ ¡ ¡SPARKS: ¡165633686 ¡(105 ¡converted, ¡0 ¡overflowed, ¡0 ¡dud, ¡165098698 ¡GC'd, ¡534883 ¡fizzled) ¡ ¡ ¡ ¡INIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.00s ¡elapsed) ¡ ¡ ¡MUT ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡2.31s ¡ ¡( ¡ ¡1.98s ¡elapsed) ¡ ¡ ¡GC ¡ ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡7.58s ¡ ¡( ¡ ¡0.51s ¡elapsed) ¡ ¡ ¡EXIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.00s ¡elapsed) ¡ ¡ ¡Total ¡ ¡ ¡+me ¡ ¡ ¡ ¡9.89s ¡ ¡( ¡ ¡2.49s ¡elapsed) ¡
331160281 ¡ ¡ ¡ ¡ ¡ ¡… ¡ ¡ ¡SPARKS: ¡165633686 ¡(105 ¡converted, ¡0 ¡overflowed, ¡0 ¡dud, ¡165098698 ¡GC'd, ¡534883 ¡fizzled) ¡ ¡ ¡ ¡INIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.00s ¡elapsed) ¡ ¡ ¡MUT ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡2.31s ¡ ¡( ¡ ¡1.98s ¡elapsed) ¡ ¡ ¡GC ¡ ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡7.58s ¡ ¡( ¡ ¡0.51s ¡elapsed) ¡ ¡ ¡EXIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.00s ¡elapsed) ¡ ¡ ¡Total ¡ ¡ ¡+me ¡ ¡ ¡ ¡9.89s ¡ ¡( ¡ ¡2.49s ¡elapsed) ¡
converted ¡= ¡turned ¡into ¡ useful ¡parallelism ¡
tfib :: Integer -> Integer -> Integer tfib t n | n < t = sfib n tfib t n = nf1 `par` nf2 `pseq` nf1 + nf2 + 1 where nf1 = tfib t (n-1) nf2 = tfib t (n-2)
¡ SPARKS: ¡88 ¡(13 ¡converted, ¡0 ¡overflowed, ¡0 ¡dud, ¡0 ¡GC'd, ¡75 ¡fizzled) ¡ ¡ ¡ ¡INIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.01s ¡elapsed) ¡ ¡ ¡MUT ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡2.42s ¡ ¡( ¡ ¡1.36s ¡elapsed) ¡ ¡ ¡GC ¡ ¡ ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡3.04s ¡ ¡( ¡ ¡0.04s ¡elapsed) ¡ ¡ ¡EXIT ¡ ¡ ¡ ¡+me ¡ ¡ ¡ ¡0.00s ¡ ¡( ¡ ¡0.00s ¡elapsed) ¡ ¡ ¡Total ¡ ¡ ¡+me ¡ ¡ ¡ ¡5.47s ¡ ¡( ¡ ¡1.41s ¡elapsed) ¡ ¡ ¡ nib ¡32 ¡40 ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡gives ¡
The ¡division ¡of ¡the ¡work ¡into ¡possible ¡parallel ¡ ¡tasks ¡ ¡(par) ¡ ¡ ¡including ¡ choosing ¡size ¡of ¡tasks ¡ GHC ¡run+me ¡takes ¡care ¡of ¡choosing ¡which ¡sparks ¡to ¡actually ¡evaluate ¡ in ¡parallel ¡and ¡of ¡distribu+on ¡ ¡ ¡ ¡Need ¡also ¡to ¡control ¡order ¡of ¡evalua+on ¡(pseq) ¡and ¡degree ¡of ¡ evalua+on ¡ ¡ Dynamic ¡behaviour ¡is ¡the ¡term ¡used ¡for ¡how ¡a ¡pure ¡func+on ¡gets ¡ par++oned, ¡distributed ¡and ¡run ¡ ¡ Remember, ¡this ¡is ¡determinis+c ¡parallelism. ¡The ¡answer ¡is ¡always ¡the ¡ same! ¡
Don’t ¡need ¡to ¡ ¡express ¡communica+on ¡ ¡express ¡synchronisa+on ¡ ¡deal ¡with ¡threads ¡explicitly ¡
par ¡and ¡pseq ¡are ¡difficult ¡to ¡use ¡L ¡ ¡ ¡
par ¡and ¡pseq ¡are ¡difficult ¡to ¡use ¡L ¡ ¡ MUST ¡ Pass ¡an ¡unevaluated ¡computa+on ¡to ¡par ¡ ¡It ¡must ¡be ¡somewhat ¡expensive ¡ Make ¡sure ¡the ¡result ¡is ¡not ¡needed ¡for ¡a ¡bit ¡ Make ¡sure ¡the ¡result ¡is ¡shared ¡by ¡the ¡rest ¡of ¡the ¡ program ¡ ¡ ¡
par ¡and ¡pseq ¡are ¡difficult ¡to ¡use ¡L ¡ ¡ MUST ¡ Pass ¡an ¡unevaluated ¡computa+on ¡to ¡par ¡ ¡It ¡must ¡be ¡somewhat ¡expensive ¡ Make ¡sure ¡the ¡result ¡is ¡not ¡needed ¡for ¡a ¡bit ¡ Make ¡sure ¡the ¡result ¡is ¡shared ¡by ¡the ¡rest ¡of ¡the ¡ program ¡ ¡ ¡
slow ¡
par ¡and ¡pseq ¡are ¡difficult ¡to ¡use ¡L ¡ ¡ MUST ¡ Pass ¡an ¡unevaluated ¡computa+on ¡to ¡par ¡ ¡It ¡must ¡be ¡somewhat ¡expensive ¡ Make ¡sure ¡the ¡result ¡is ¡not ¡needed ¡for ¡a ¡bit ¡ Make ¡sure ¡the ¡result ¡is ¡shared ¡by ¡the ¡rest ¡of ¡the ¡ program ¡ ¡ ¡
GC ¡
Original ¡code ¡+ ¡par ¡+ ¡pseq ¡+ ¡rnf ¡etc. ¡ can ¡be ¡opaque ¡
Algorithm ¡
Algorithm ¡ Evalua+on ¡Strategy ¡
express ¡dynamic ¡behaviour ¡independent ¡of ¡the ¡ algorithm ¡ ¡ provide ¡abstrac+ons ¡above ¡par ¡and ¡pseq ¡ ¡ are ¡modular ¡and ¡composi+onal ¡ ¡ ¡ ¡ ¡ ¡ ¡ (they ¡are ¡ordinary ¡higher ¡order ¡func+ons) ¡ ¡ can ¡capture ¡pa>erns ¡of ¡parallelism ¡ ¡ ¡
H ¡
JFP ¡1998 ¡ Haskell’10 ¡
H ¡
JFP ¡1998 ¡ Haskell’10 ¡
330 ¡
H ¡
JFP ¡1998 ¡ Haskell’10 ¡
330 ¡ 71 ¡
H ¡
JFP ¡1993 ¡ Haskell’10 ¡ ¡ Redesigns ¡strategies ¡ ¡ richer ¡set ¡of ¡parallelism ¡combinators ¡ Be>er ¡specs ¡(evalua+on ¡order) ¡ ¡ Allows ¡new ¡forms ¡of ¡coordina+on ¡ generic ¡regular ¡strategies ¡over ¡data ¡ structures ¡ specula+ve ¡parellelism ¡ monads ¡everywhere ¡J ¡ ¡ Presenta+on ¡is ¡about ¡New ¡Strategies ¡ ¡
¡
Slide ¡borrowed ¡from ¡Simon ¡Marlow’s ¡CEFP ¡slides, ¡with ¡thanks ¡
Slide ¡borrowed ¡from ¡Simon ¡Marlow’s ¡CEFP ¡slides, ¡with ¡thanks ¡
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1)
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1)
¡
do ¡ ¡this ¡ ¡ ¡ ¡ spark ¡qfib ¡(n-‑1) ¡ ¡
"My ¡argument ¡could ¡be ¡evaluated ¡in ¡parallel" ¡
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1)
¡
do ¡ ¡this ¡ ¡ ¡ ¡ spark ¡nfib ¡(n-‑1) ¡ ¡
"My ¡argument ¡could ¡be ¡evaluated ¡in ¡parallel" ¡ "My ¡argument ¡could ¡be ¡evaluated ¡in ¡parallel” ¡ ¡ Remember ¡that ¡the ¡argument ¡should ¡be ¡a ¡thunk! ¡
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1)
¡
and ¡then ¡this ¡ Evaluate ¡qfib(n-‑2) ¡ and ¡wait ¡for ¡ result ¡ ¡ ¡
"Evaluate ¡my ¡argument ¡and ¡wait ¡for ¡the ¡result." ¡
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1) the ¡result ¡
qfib :: Integer -> Integer qfib n | n < 2 = 1 qfib n = runEval $ do nf1 <- rpar (qfib (n-1)) nf2 <- rseq (qfib (n-2)) return (nf1 + nf2 + 1) pull ¡the ¡answer ¡
monad ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rpar ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rpar ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡ f ¡ ¡x ¡ f ¡ ¡y ¡ return ¡ +me ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rseq ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡ f ¡ ¡x ¡ f ¡ ¡y ¡ return ¡ +me ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rseq ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡ f ¡ ¡x ¡ F ¡y ¡ return ¡ +me ¡ Not ¡completely ¡sa+sfactory ¡ Unlikely ¡to ¡know ¡which ¡one ¡to ¡ wait ¡for ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rseq ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡rseq ¡a ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡ f ¡ ¡x ¡ F ¡y ¡ return ¡ +me ¡
runEval ¡$ ¡do ¡ ¡ ¡ ¡ ¡ ¡a ¡<-‑ ¡rpar ¡(f ¡x) ¡ ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rseq ¡(f ¡y) ¡ ¡ ¡ ¡ ¡ ¡rseq ¡a ¡ ¡ ¡ ¡ ¡ ¡return ¡(a,b) ¡ f ¡ ¡x ¡ F ¡y ¡ return ¡ +me ¡ Choice ¡between ¡rpar/rpar ¡and ¡ ¡ rpar/rseq/rseq ¡will ¡depend ¡on ¡ circumstances ¡(see ¡PCPH ¡ch. ¡2) ¡
The ¡Eval ¡monad ¡raises ¡the ¡level ¡of ¡abstrac+on ¡for ¡pseq ¡and ¡par; ¡ it ¡makes ¡fragments ¡of ¡evalua+on ¡order ¡first ¡class, ¡and ¡lets ¡us ¡ compose ¡them ¡together. ¡We ¡should ¡think ¡of ¡the ¡Eval ¡monad ¡as ¡ an ¡Embedded ¡Domain-‑Specific ¡Language ¡(EDSL) ¡for ¡expressing ¡ evalua+on ¡order, ¡embedding ¡a ¡li>le ¡evalua+on-‑order ¡ constrained ¡language ¡inside ¡Haskell, ¡which ¡does ¡ not ¡have ¡a ¡strongly-‑defined ¡evalua+on ¡order. ¡ ¡ (from ¡ ¡Haskell ¡10 ¡paper) ¡
pMap :: (a -> b) -> [a] -> Eval [b] pMap f [] = return [] pMap f (a:as) = do b <- rpar (f a) bs <- pMap f as return (b:bs)
print ¡$ ¡sum ¡$ ¡runEval ¡$ ¡(foo ¡[1..10000] ¡(reverse ¡[1..10000])) ¡ SPARKS: ¡10000 ¡(8194 ¡converted, ¡1806 ¡overflowed, ¡0 ¡dud, ¡0 ¡GC'd, ¡0 ¡fizzled) ¡ print $ sum $ runEval $ (parMap foo (reverse [1..10000])) foo :: Integer -> Integer foo = \a -> sum [1 .. a]
print ¡$ ¡sum ¡$ ¡runEval ¡$ ¡(foo ¡[1..10000] ¡(reverse ¡[1..10000])) ¡ SPARKS: ¡10000 ¡(8194 ¡converted, ¡1806 ¡overflowed, ¡0 ¡dud, ¡0 ¡GC'd, ¡0 ¡fizzled) ¡ print $ sum $ runEval $ (parMap foo (reverse [1..10000]))
#sparks ¡= ¡ length ¡of ¡list ¡
foo :: Integer -> Integer foo = \a -> sum [1 .. a]
converted ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡real ¡parallelism ¡at ¡run+me ¡ ¡
¡ dud ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡first ¡arg ¡of ¡rpar ¡already ¡eval’ed ¡ ¡ GC’d ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡sparked ¡expression ¡unused ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡(removed ¡from ¡spark ¡pool) ¡ ¡ fizzled ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡uneval’d ¡when ¡sparked, ¡later ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡eval’d ¡indepently ¡=> ¡removed ¡ ¡
parMap ¡:: ¡(a ¡-‑> ¡b) ¡-‑> ¡[a] ¡-‑> ¡Eval ¡[b] ¡ parMap ¡f ¡[] ¡= ¡return ¡[] ¡ parMap ¡f ¡(a:as) ¡= ¡do ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rpar ¡(f ¡a) ¡ ¡ ¡ ¡ ¡bs ¡<-‑ ¡parMap ¡f ¡as ¡ ¡ ¡ ¡ ¡return ¡(b:bs) ¡
+ ¡Captures ¡a ¡pa>ern ¡of ¡parallelism ¡ + ¡good ¡to ¡do ¡this ¡for ¡standard ¡higher ¡ ¡order ¡func+on ¡like ¡map ¡ + ¡can ¡easily ¡do ¡this ¡for ¡other ¡standard ¡sequen+al ¡pa>erns ¡
parMap ¡:: ¡(a ¡-‑> ¡b) ¡-‑> ¡[a] ¡-‑> ¡Eval ¡[b] ¡ parMap ¡f ¡[] ¡= ¡return ¡[] ¡ parMap ¡f ¡(a:as) ¡= ¡do ¡ ¡ ¡ ¡ ¡b ¡<-‑ ¡rpar ¡(f ¡a) ¡ ¡ ¡ ¡ ¡bs ¡<-‑ ¡parMap ¡f ¡as ¡ ¡ ¡ ¡ ¡return ¡(b:bs) ¡
Raise ¡level ¡of ¡abstrac+on ¡ ¡ Encapsulate ¡parallel ¡programming ¡idioms ¡as ¡ reusable ¡components ¡that ¡can ¡be ¡composed ¡
type Strategy a = a -> Eval a func+on ¡ ¡ evaluates ¡its ¡input ¡ ¡to ¡some ¡degree ¡ ¡ traverses ¡its ¡argument ¡and ¡uses ¡rpar ¡and ¡rseq ¡to ¡express ¡dynamic ¡ behaviour ¡/ ¡sparking ¡ ¡ returns ¡an ¡equivalent ¡value ¡in ¡the ¡Eval ¡monad ¡ ¡ ¡
using :: a -> Strategy a -> a x `using` strat = runEval (strat x)
Program ¡typically ¡applies ¡the ¡strategy ¡to ¡a ¡structure ¡and ¡then ¡uses ¡the ¡returned ¡value, ¡ discarding ¡the ¡original ¡one ¡ ¡(which ¡is ¡why ¡the ¡value ¡had ¡be>er ¡be ¡equivalent) ¡ ¡ ¡ An ¡almost ¡iden+ty ¡func+on ¡that ¡does ¡some ¡evalua+on ¡and ¡expresses ¡how ¡that ¡can ¡ be ¡parallelised ¡
r0 :: Strategy a r0 x = return x rpar :: Strategy a rpar x = x `par` return x rseq :: Strategy a rseq x = x `pseq` return x rdeepseq :: NFData a => Strategy a rdeepseq x = rnf x `pseq` return x
r0 :: Strategy a r0 x = return x rpar :: Strategy a rpar x = x `par` return x rseq :: Strategy a rseq x = x `pseq` return x rdeepseq :: NFData a => Strategy a rdeepseq x = rnf x `pseq` return x NO ¡evalua+on ¡
r0 :: Strategy a r0 x = return x rpar :: Strategy a rpar x = x `par` return x rseq :: Strategy a rseq x = x `pseq` return x rdeepseq :: NFData a => Strategy a rdeepseq x = rnf x `pseq` return x ¡ ¡ ¡spark ¡ ¡x ¡
r0 :: Strategy a r0 x = return x rpar :: Strategy a rpar x = x `par` return x rseq :: Strategy a rseq x = x `pseq` return x rdeepseq :: NFData a => Strategy a rdeepseq x = rnf x `pseq` return x ¡ ¡ ¡evaluate ¡x ¡ to ¡WHNF ¡
r0 :: Strategy a r0 x = return x rpar :: Strategy a rpar x = x `par` return x rseq :: Strategy a rseq x = x `pseq` return x rdeepseq :: NFData a => Strategy a rdeepseq x = rnf x `pseq` return x ¡ ¡ ¡ ¡fully ¡evaluate ¡x ¡
evalList :: Strategy a -> Strategy [a] evalList s [] = return [] evalList s (x:xs) = do x’ <- s x xs’ <- evalList s xs return (x’:xs’)
evalList :: Strategy a -> Strategy [a] evalList s [] = return [] evalList s (x:xs) = do x’ <- s x xs’ <- evalList s xs return (x’:xs’) Takes ¡a ¡Strategy ¡on ¡a ¡and ¡returns ¡a ¡Strategy ¡
Building ¡strategies ¡from ¡smaller ¡ones ¡
evalList :: Strategy a -> Strategy [a] evalList s [] = return [] evalList s (x:xs) = do x’ <- s x xs’ <- evalList s xs return (x’:xs’) parList :: Strategy a -> Strategy [a] parList s = evalList (rpar `dot` s)
evalList :: Strategy a -> Strategy [a] evalList s [] = return [] evalList s (x:xs) = do x’ <- s x xs’ <- evalList s xs return (x’:xs’) parList :: Strategy a -> Strategy [a] parList s = evalList (rpar `dot` s) dot :: Strategy a -> Strategy a -> Strategy a s2 ‘dot‘ s1 = s2 . runEval . s1
evalList :: Strategy a -> Strategy [a] evalList = evalTraversable parList :: Strategy a -> Strategy [a] parList = parTraversable
evalList :: Strategy a -> Strategy [a] evalList = evalTraversable parList :: Strategy a -> Strategy [a] parList = parTraversable ¡ The ¡equivalent ¡of ¡evalList ¡and ¡of ¡parList ¡are ¡available ¡for ¡many ¡ ¡data ¡structures ¡(Traversable). ¡ ¡ ¡So ¡defining ¡parX ¡ ¡ ¡for ¡many ¡X ¡ ¡ ¡ ¡is ¡really ¡easy ¡ ¡ => ¡ ¡generic ¡strategies ¡for ¡data-‑oriented ¡parallelism ¡
parListSplitAt :: Int -> Strategy [a] -> Strategy [a]
parListSplitAt n stratL stratR stratR ¡ stratL ¡ n ¡ par ¡
parListChunk :: Int -> Strategy a -> Strategy [a] ¡ . ¡. ¡. ¡ n ¡ parListChunk n strat ¡ evalList strat ¡ . ¡. ¡. ¡
parListChunk :: Int -> Strategy a -> Strategy [a] ¡ ¡ ¡ SPARKS: ¡200 ¡(200 ¡converted, ¡0 ¡overflowed, ¡0 ¡dud, ¡0 ¡GC'd, ¡0 ¡fizzled) ¡
print $ sum $ runEval $ parMap foo (reverse [1..10000])
Now ¡
print $ sum $ (map foo (reverse [1..10000]) `using` parListChunk 50 rdeepseq )
Before ¡
parListChunk :: Int -> Strategy a -> Strategy [a] ¡ ¡ ¡ SPARKS: ¡200 ¡(200 ¡converted, ¡0 ¡overflowed, ¡0 ¡dud, ¡0 ¡GC'd, ¡0 ¡fizzled) ¡
print $ sum $ runEval $ parMap foo (reverse [1..10000])
Now ¡
print $ sum $ (map foo (reverse [1..10000]) `using` parListChunk 50 rdeepseq )
Before ¡
Remember ¡not ¡to ¡be ¡a ¡control ¡freak, ¡though. ¡ Genera+ng ¡plenty ¡of ¡sparks ¡gives ¡the ¡ run+me ¡the ¡freedom ¡it ¡needs ¡to ¡make ¡good ¡ choices ¡ ¡ ¡(=> ¡Dynamic ¡par++oning ¡for ¡free) ¡
using ¡is ¡not ¡always ¡what ¡we ¡need ¡
coordina+on ¡in ¡qfib ¡(from ¡earlier) ¡doesn’t ¡ really ¡give ¡a ¡sa+sfactory ¡answer ¡(see ¡Haskell ¡ 10 ¡paper) ¡ ¡(If ¡the ¡worst ¡comes ¡to ¡the ¡worst, ¡one ¡can ¡get ¡ explict ¡control ¡of ¡threads ¡etc. ¡in ¡concurrent ¡ Haskell, ¡but ¡determinism ¡is ¡lost… ¡ ¡) ¡
Capturing ¡pa>erns ¡of ¡parallel ¡computa+on ¡is ¡a ¡ major ¡strong ¡point ¡of ¡strategies ¡ D&C ¡is ¡a ¡typical ¡example ¡(see ¡also ¡parBuffer, ¡ parallel ¡pipelines ¡etc.) ¡
divConq :: (a -> b)
func+on ¡on ¡base ¡cases ¡ input ¡ par ¡threshold ¡reached? ¡ combine ¡ divide ¡ result ¡
divConq f arg threshold combine divide = go arg where go arg = case divide arg of Nothing -> f arg Just (l0,r0) -> combine l1 r1 ‘using‘ strat where l1 = go l0 r1 = go r0 strat x = do r l1; r r1; return x where r | threshold arg = rseq | otherwise = rpar Separates ¡ ¡algorithm ¡and ¡strategy ¡ A ¡first ¡inkling ¡that ¡one ¡can ¡probably ¡do ¡interes+ng ¡things ¡by ¡programming ¡with ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡strategies ¡
and ¡provide ¡efficient ¡parallel ¡implementa+ons ¡(Cole, ¡ 1989) ¡
A ¡difference: ¡one ¡can ¡/ ¡should ¡roll ¡ones ¡own ¡strategies ¡ ¡ See ¡the ¡guest ¡lecture ¡by ¡David ¡Duke ¡
+ ¡ ¡elegant ¡redesign ¡by ¡Marlow ¡et ¡al ¡ ¡ ¡(Haskell ¡10) ¡ ¡ + ¡ ¡be>er ¡separa+on ¡of ¡concerns ¡ ¡ + ¡ ¡Laziness ¡is ¡essen+al ¡for ¡modularity ¡ ¡ + ¡ ¡ ¡generic ¡strategies ¡for ¡(Traversable) ¡data ¡structures ¡ ¡ + ¡ ¡ ¡Marlow’s ¡book ¡contain ¡a ¡nice ¡kmeans ¡example. ¡Read ¡it! ¡ ¡
Laziness ¡is ¡not ¡only ¡good ¡here. ¡ ¡(Cue ¡the ¡Par ¡Monad ¡Lecture!) ¡
Algorithm ¡ Evalua+on ¡Strategy ¡
Simon ¡Marlow’s ¡landscape ¡for ¡parallel ¡ Haskell ¡
– par/pseq& – Strategies& – Par&Monad& – Repa& – Accelerate& – DPH&
– forkIO& – MVar& – STM& – async& – Cloud&Haskell&
Haxl?&
1 3 2 4 Simon ¡ Marlow ¡ lecture ¡J ¡ ¡
Read ¡papers ¡and ¡PCPH ¡ ¡ Start ¡on ¡Lab ¡A ¡(due ¡noon ¡April ¡18) ¡ ¡ ¡ ¡ ¡Note ¡office ¡hours ¡of ¡TAs ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Markus, ¡mon ¡11-‑12 ¡and ¡tues ¡10-‑11 ¡ ¡Nick, ¡wed ¡13-‑14 ¡and ¡fri ¡13-‑14) ¡ ¡Use ¡them! ¡ Happy ¡Easter! ¡