为什么putStrLn不是原子的?

时间:2014-09-07 13:14:24

标签: haskell concurrency

为了练习并发编程,我编写了以下(次优)程序,它重复计算第一个素数大于用户输入的值:

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

我希望在后台有一个工作线程进行实际计算,并在完成后立即输出(n, primeAtLeast n)

它现在正在做什么:只要我输入一个数字n,它就立即输出(n,,将控件返回到主线程,计算出primeAtLeast n背景并在下半场结束时输出primeAtLeast n)

那么putStrLn不是原子的吗?或问题出在哪里?

1 个答案:

答案 0 :(得分:3)

试试这个:

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

以上强制在putStrLn运行之前计算素数。

此外,您可以使用print代替putStrLn . show

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

或者,您可以使用putStrLn函数在开始打印任何内容之前强制每个字符。

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