[Haskell-cafe] Re[6]: Parallel combinator, performance advice

Bulat Ziganshin bulat.ziganshin at gmail.com
Tue Apr 7 12:40:06 EDT 2009

Hello Bulat,

Tuesday, April 7, 2009, 8:10:43 PM, you wrote:

>>> parallel_ (x1:xs) = do
>>>     sem <- newQSem $ 1 - length xs
>>>     forM_ xs $ \x ->
>>>         writeChan queue (x >> signalQSem sem, False)
>>>     x1
>>>     addWorker
>>>     waitQSem sem
>>>     writeChan queue (signalQSem sem, True)
>>>     waitQSem sem

>> Neil, executing x1 directly in parallel_ is incorrect idea.

> forget this. but it still a bit suboptimal...

i think i realized why you use this schema. my solution may lead to
N-1 worker threads in the system if last job is too small - after its
execution we finish one thread and have just N-1 working threads until
parallel_ will be finished

but problem i mentioned in previous letter may also take place
although it looks like less important. we may solve both problems by
allowing worker thread to actively select its death time: it should
die only at the moment when *last* job in bucket was finished - this
guarantees us exactly N worker threads at any time. so:

parallel_ (x1:xs) = do
    sem <- newQSem $ - length xs
    jobsLast <- newMVar (length xs)
    forM_ (x1:xs) $ \x -> do
        writeChan queue $ do
           signalQSem sem
           modifyMVar jobsLast $ \jobs -> do
               return (jobs-1, jobs==0)
    waitQSem sem

and modify last 3 lines of addWorker:

addWorker :: IO ()
addWorker = do
    forkIO $ f `E.catch` \(e :: SomeException) ->
        throwTo mainThread $ ErrorCall "Control.Concurrent.Parallel: parallel thread died."
    return ()
        f :: IO ()
        f = do
            act <- readChan queue
            kill <- act
            unless kill f

Best regards,
 Bulat                            mailto:Bulat.Ziganshin at gmail.com

More information about the Haskell-Cafe mailing list