为了练习并发编程,我编写了以下(次优)程序,它重复计算第一个素数大于用户输入的值:
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
不是原子的吗?或问题出在哪里?
答案 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