【问题标题】:ThreadDelay Outside the Main Thread主线程外的 ThreadDelay
【发布时间】:2014-06-29 15:27:15
【问题描述】:

我一直在尝试编写一个函数,它可以逐个字母地打印出一个字符串,不带引号,并在每个字母之间暂停一点。例如,如果你给它“hello”,它会打印 h,然后等待,e,然后等待,然后 l,然后等待,然后 l,然后等待,o。但是当我尝试使用threadDelay 时,它会在主线程中暂停。所以它会暂停,然后一次打印所有内容。我试图在prints 函数中创建一个新线程,但它不起作用。帮助!

import Control.Concurrent as C

clean :: String -> String
clean s@[c]               = s
clean ('"':s)  
    | last s == '"'       = init s
    | otherwise           = s
clean ('\'':s) 
    | last s == '\''      = init s           
    | otherwise           = s
clean s                   = s

prints :: String -> IO()
prints [] = putStrLn " "
prints (x:xs) = do
    C.forkIO $ do
        putStr $ clean (show x)
        C.threadDelay $ 10000
        prints xs  

main :: IO()
main = do 
    prints "hello"

【问题讨论】:

  • 以下对我有用:prints = sequence_ . intersperse (threadDelay (10^5)) . map (putStr . return); main = hSetBuffering stdout NoBuffering >> prints "hello".
  • @user2407038 : 什么平台?
  • @GaneshSittampalam Windows 和 Mac(在虚拟机中,但这不重要)

标签: multithreading haskell concurrency


【解决方案1】:

您的代码有一些问题。

首先,threadDelay微秒 内接受一个参数,因此您添加的暂停太小而无法注意到。试试1000000

其次,除非您在 stdout 上关闭缓冲,否则 IO 库将缓冲您的输出,因此您不会看到预期的延迟。你可以用System.IO控制这个:

import System.IO ( stdout, hSetBuffering, BufferMode(..) )

然后从main调用hSetBuffering

hSetBuffering stdout NoBuffering

最后,分叉一个线程实际上是倒退了一步,因为程序不会等待分叉的线程完成,所以只需删除它。如果您真的希望它在后台运行,则需要使用 MVar 或类似的方法等待它完成,否则程序会自然先退出。

【讨论】:

  • 如果你按照我的建议使用一百万的延迟,而不是我认为的十万,它是否有效?十万的我只能看到慢慢的,但已经接近人类感知的极限了。你所拥有的正是我所测试的,除了那个差异。
  • 不,它只是暂停了很长时间,然后将所有内容都打印出来。
  • 这是我的代码,以防我忘记任何其他区别:lpaste.net/106474 在 Windows 和 Linux 上的每个字符之间肯定会暂停一秒钟。
  • 是否在putStr 帮助后添加hFlush stdout(您还需要从System.IO 导入hFlush)?我不知道发生了什么,所以只是建议一些随机的东西......
猜你喜欢
  • 2013-05-05
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2013-04-09
  • 2021-12-11
相关资源
最近更新 更多