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