Haskell并发IO行为

4

我正在努力更深入地了解Haskell中的并发性。我有以下代码:

import Control.Concurrent
    main :: IO ()

    main = do 
    arr <- return $ [1..9]
    t <- newMVar 1
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    return ()

有时我会看到打印操作重叠,导致出现以下结果(请查看第二个调用):
*Main Control.Concurrent> :l test.hs 
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main Control.Concurrent> main
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
*Main Control.Concurrent> main
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
["[1,2,3,4,5,6,7,8,9]"
?"[1,2,3,4,5,6,7,8,9]"
1h*Main Control.Concurrent> 

我不明白为什么会发生这种情况。使用MVar处理[1..9]也不好。


1
相关链接:https://dev59.com/BXA85IYBdhLWcg3wBOxO - sdcvvc
问题在于主线程比子线程先结束。如果我们等待所有子线程完成,就不会出现重叠。 - Anton
另外,print = putStrLn.showprint.show 调用了两次 show,有点冗余。 - jrockway
1个回答

4

有时我看到打印操作重叠

输出有时会重叠,因为标准输出上有一个锁。每个线程调用“print”,尝试写出一个字符,并为每个字符获取锁。由于 Haskell 的抢占式并发性,您将看到随机的线程交织打印。

如果这是不希望的行为,可以让每个线程将其想要打印的字符串发送给打印机线程,然后打印机线程将按顺序逐行输出。


我理解你的意思是,Haskell的stdout会将每个字符分别打印在不同的线程中?我说得对吗? - Anton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接