Why is putStrLn not atomic?

To practice parallel programming, I wrote the following (suboptimal) program that repeatedly calculates the first prime more than anything the user enters:

import Control.Concurrent
import Control.Concurrent.Chan
import Control.Monad (forever)
primeAtLeast n = -- Some pure code that looks up the first prime at least as big as n

outputPrimeAtLeast n = putStrLn $ show $ (n, primeAtLeast n)

main = do
    chan <- newChan
    worker <- forkIO $ forever $ readChan chan >>= outputPrimeAtLeast
    forever $ (readLn :: (IO Int)) >>= (writeChan chan)
    killThread worker

      

I want to have a worker thread in the background that does the actual calculation and outputs (n, primeAtLeast n)

as soon as it ends.

What it does now: As soon as I enter a number n

, it outputs immediately (n,

, returns the control to the main thread, computes primeAtLeast n

in the background, and outputs the other half primeAtLeast n)

as soon as it finishes.

So, putStrLn

not atomic? Or where is the problem?

+3


source to share


1 answer


Try the following:

outputPrimeAtLeast n = let p = primeAtLeast n in p `seq` putStrLn $ show (n, p)

      

The above forces it to compute the space before starting putStrLn

.

Alternatively, you can use print

instead putStrLn . show

:



outputPrimeAtLeast n = let p = primeAtLeast n in p `seq` print (n, p)

      

Alternatively, you can use a function putStrLn

that forces each individual character before printing. In the meantime, there is no need to worry about it. ”

strictPutStrLn :: Show a => a -> IO ()
strictPutStrLn x = let str = show x in str `listSeq` putStrLn str

listSeq :: [a] -> b -> b
listSeq []     w = w
listSeq (x:xs) w = x `seq` listSeq xs w

      

+3


source







All Articles