350 likes | 534 Views
Parallel and Concurrent Programming in Haskell. Satnam Singh Microsoft Research Cambridge. Leeds2009. Recap. par :: a -> b -> b pseq :: a -> b -> b forceList :: [a] -> () x ` par ` (y ` pseq ` x+y ) Determinisim. a. b. c. d. l. f a. f b. f c. f d. map f l.
E N D
Parallel and Concurrent Programming in Haskell Satnam Singh Microsoft Research Cambridge Leeds2009
Recap • par :: a -> b -> b • pseq :: a -> b -> b • forceList :: [a] -> () • x `par` (y `pseq` x+y) • Determinisim
a b c d l f a f b f c f d map f l map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = f x : map f xs
3 1 7 2 l 6 2 14 4 map double l double :: Int -> Int double x = 2 * x
a b c d l f a f b f c f d parMap f l parMap :: (a -> b) -> [a] -> [b] parMap f [] = [] parMap f (x:xs) = fx `par` (fx : parMap f xs) where fx = f x
a b c d l f a f b f c f d parMap f l parMap :: (a -> b) -> [a] -> [b] parMap f [] = [] parMap f (x:xs) = fx `par` (fxs `pseq` (fx:fxs)) where fx = f x fxs= parMap f xs
a b c d l f a f b f c f d parMap f l parList :: Strategy a -> Strategy [a] parListstrat [] = () parListstrat (x:xs) = strat x `par` (parListstratxs) parMap:: Strategy b -> (a -> b) -> [a] -> [b] parMapstrat f xs = map f xs `using` parListstrat
Explicitly Creating Threads • forkIO :: IO () -> ThreadID • Creates a lightweight Haskell thread, not an operating system thread.
Inter-thread Communication • putMVar :: MVar a -> IO () • takeMVar :: MVar a -> IO a
MVars empty 52 mv ... putMVarmv 52 ... ... ... ... v <- takeMVarmv ...
Rendezvous threadA threadB send 42 42 read 42 blocked send 84 read 84 and continue
Rendezvous threadA :: MVarInt -> MVar Float -> IO () threadAvalueToSendMVarvalueReceivedMVar = do -- some work -- new perform rendezvous by sending 42 putMVarvalueToSendMVar 42 -- send value v <- takeMVarvalueToReadMVar putStrLn (show v)
Rendezvous threadB :: MVarInt -> MVar Float -> IO () threadBvalueToReceiveMVarvalueToSendMVar = do -- some work -- now perform rendezvous by waiting on value z <- takeMVarvalueToReceiveMVar putMVarvalueToSendMVar (2 * z) -- continue with other work
Rendezvous main :: IO () main = do aMVar <- newEmptyMVar bMVar <- newEmptyMVar forkIO (threadAaMVarbMVar) forkIO (threadBaMVarbMVar) threadDelay 1000 -- BAD!
A function that does some work fib :: Integer -> Integer fib 0 = 0 fib 1 = 1 fib n = fib (n-1) + fib (n-2)
Asynchronous Call fibThread :: Int -> MVarInt -> IO () fibThread n resultMVar = putMVarresultMVar (fib n) resultMVar <- newEmptyMVar forkIO (fibThread30resultMVar) seq (fib 30) (return ()) result <- takeMVarresultMVar
$ time fibForkIO +RTS -N1 real 0m40.473s user 0m0.000s sys 0m0.031s $ time fibForkIO +RTS -N2 real 0m38.580s user 0m0.000s sys 0m0.015s
putMVarresultMVar (fib 30) resultMVar resultMVar 83204 fib 30 thunk for computing fib 30
Inter-thread Communication 2 • putTVar:: TVara -> STM() • takeTVar:: TVara -> STM a • atomically :: STM a -> IO a
TVars empty 52 tv ... atomically (putTVarmv52) ... ... ... ... v <- atomically (takeTVarmv) ...
retry do v <- readTVar bal if v< 10 then retry else writeTVar bal (v-10)
Reading the first arrival... q2 q1 atomically (doi<- “readTVar q1 or if q1 empty readTVarq2” ; writeTVar r i ) r