Talk:Parallelism vs. Concurrency
Jump to navigation
Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Parallelism vs concurrency: what's the difference?
Visible side effects.
- Have a look at this
ugly eysore"prototype definition" ofpar
:
par :: a -> b -> b par x y = case unsafeLocalState (forkIO (evaluate x >> return ())) of !_ -> y
where:
evaluate :: a -> IO a forkIO :: IO () -> IO ThreadId
Assuming:
x
is well-defined (it contains nounsafe...
calls),x
is well-behaved (not throwing exceptions or causing errors);
then:
forkIO
attaches aThreadId
to its argument, adds it to the work-queue and returns the identifier;par
then returnsy
;- Some time later,
forkIO
's argument is called, causingevaluate
to start evaluatingx
.
If
y
is still being evaluated when the evaluation ofx
commences, then we have concurrency, but with no visible side-effects - elementary parallelism.
- Now have a look at this
nearly-as-uglyprototype definition forspawnIO
forkIO
:
forkIO :: IO () -> IO ThreadId forkIO act = do t <- unsafeInterleaveIO act case attachThreadId t of Nothing -> itsThreadId t Just i -> par t (return i)
where:
attachThreadId :: a -> IO (Maybe ThreadId) itsThreadId :: a -> IO ThreadId
Assuming:
par
,attachThreadId
anditsThreadId
are primitive,attachThreadId
would returnNothing
if it's argument already has been assigned aThreadId
;
then:
- A new
ThreadId
is assigned to the new (and suspended) valuet
; - evaluating
par t i
causest
to be added to the work-queue by the implementation; - the
ThreadId
fort
is then returned; - Some time later, the implementation discovers that a
ThreadId
has been attached tot
and uses theThreadId
to immediately start a new thread for evaluatingt
;
This is parallelism, but having visible side effects - it looks very much like elementary concurrency.
Can either of these prototypes ever go mainstream?
- As shown by it's type signature,
par
is supposed to be pure: avoiding the use ofunsafeLocalState
means making it primitive; - While the use of
unsafeInterleaveIO
may annoy some, it being one of the earlier Haskell extensions means it's widely available.
For now, using a primitive par
(and others) to define forkIO
looks like the simplest option...but if using unsafeInterleaveIO
really does annoy you, how about this:
forkIO :: (OI -> ()) -> OI -> ThreadId forkIO act u = let !(u1:u2:u3:_) = parts u in let t = act u1 in case attachThreadId t u2 of Nothing -> itsThreadId t u3 Just i -> par t i
-- Atravers Tue Apr 20 06:04:10 UTC 2021