Difference between revisions of "Talk:Parallelism vs. Concurrency"
Jump to navigation
Jump to search
m (Terminology changed) |
|||
Line 66: | Line 66: | ||
* While the use of <code>unsafeInterleaveIO</code> may annoy some, it being one of the earlier Haskell extensions means it's widely available. |
* While the use of <code>unsafeInterleaveIO</code> may annoy some, it being one of the earlier Haskell extensions means it's widely available. |
||
− | For now, using a primitive <code>par</code> (and others) to define <code>forkIO</code> looks like the simplest option...but if using <code>unsafeInterleaveIO</code> ''really does'' annoy you, how about [[IO |
+ | For now, using a primitive <code>par</code> (and others) to define <code>forkIO</code> looks like the simplest option...but if using <code>unsafeInterleaveIO</code> ''really does'' annoy you, how about [[IO in action|this]]: |
:<haskell> |
:<haskell> |
Latest revision as of 21:29, 14 June 2022
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 - it behaves like 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 behaves like elementary concurrency.
Can either prototype definition potentially go mainstream?
- As shown by it's type signature,
par
is meant to have no visible effects: 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