Talk:Parallelism vs. Concurrency

From HaskellWiki
Revision as of 06:24, 20 April 2021 by Atravers (talk | contribs) (Minor changes)
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" of par:
par     :: a -> b -> b
par x y =  case
             unsafeLocalState (forkIO (evalIO x >> return ()))
           of
             !_ -> y

where:

      evalIO :: a -> IO a
      forkIO :: IO () -> IO ThreadId

Assuming:

  • x is well-defined (it contains no unsafe... calls),
  • x is well-behaved (not throwing exceptions or causing errors);

then:

  1. forkIO attaches a ThreadId to its argument, adds it to the work-queue and returns the identifier;
  2. par then returns y;
  3. Some time later, forkIO's argument is called, causing evalIO to start evaluating x.

If y is still being evaluated when the evaluation of x commences, then we have elementary parallelism: concurrency, but with no visible side-effects.

  • Now have a look at this equally-as-ugly prototype definition for spawnIO forkIO:
forkIO     :: IO () -> IO ThreadId
forkIO act =  do let t = unsafeLocalState act
                 case par t () of
                   !_ -> do i' <- itsThreadId t
                            case i' of
                              Just i  -> return i
                              Nothing -> ioError "forkIO"

where:

      itsThreadId :: a -> IO (Maybe ThreadId)

Assuming:

  • par and itsThreadId are primitive,
  • itsThreadId would return Nothing if it's argument had not been previously used by par;

then:

  1. Evaluating par t () causes a new ThreadId to be attached to t by the implementation;
  2. itsThreadId retrieves i', the (possible) identifier for t;
  3. forkIO then extracts and returns the identifier.

This looks very much like elementary concurrency: parallelism, but having visible side effects.

Can either of these prototypes ever go mainstream?

  • As shown by it's type signature, par is supposed to be pure: avoiding the use of unsafeLocalState means making it primitive;
  • Considering it's already IO-based, forkIO without unsafeLocalState seems more likely.

This looks interesting:

forkIO       :: (OI -> ()) -> IO -> ThreadId
forkIO act u =  let !(u1:u2:u3:_) = parts u in
                let t             = act u1 in
                case par t () of
                  !_ -> case itsThreadId t u2 of
                          Just i  -> i
                          Nothing -> ioError "forkIO" u3

-- Atravers Tue Apr 20 06:04:10 UTC 2021