我有一个函数,可以使用forkIO派生到线程中。该函数在ReaderT monad transformer中运行,以便我可以传递只读配置记录:
main :: IO ()
main = do
...
forkIO $ runReaderT watcher config
watcher
函数使用tryTakeMVar监视MVar(我不想阻止它。)MVar存储在配置中,并称为“抽屉”,因为它的行为类似于事务抽屉在main
和watcher
正在监视的线程之间切换,基本上是一个跳过频道。
printThing
的签名为printThing :: Thing -> ReaderT Config IO ()
,并调用putStrLn
打印Thing
。
watcher :: ReaderT Config IO ()
watcher = do
cfg <- ask
mNewThing <- liftIO $ tryTakeMVar $ drawer cfg
case mNewThing of
Nothing -> do
--liftIO $ putStr "" -- uncommenting this helps
watcher
Just newThing -> do
printThing newThing
watcher
问题是程序在运行时挂起。它似乎陷入了循环。在putStr ""
中调用main
并没有帮助,但是,在putStr ""
内部调用watcher
会触发线程-它开始旋转并打印出Thing
预期的。
我能想出的是,我被懒惰所咬,但是我不确定在哪里。我尝试过在可能的情况下使用$!
。
我在watcher
的某些条件下执行IO操作,但不是全部。那是问题吗?我需要在所有条件分支中执行IO操作吗?
如果有帮助,在将所有内容包装在ReaderT
转换器中之前,我没有这个问题。我只是在传递config
作为参数。
答案 0 :(得分:3)
尽管您的问题中有文字,我还是建议您让watcher
阻止。确实很少需要在MVar
上执行非阻塞操作。通常希望它是sign you haven't quite internalized the "fork everything" mentality。所以:
watcher :: ReaderT Config IO ()
watcher = do
cfg <- ask
newThing <- liftIO . takeMVar $ drawer cfg
printThing newThing
watcher
我们可以单独解决一个问题,形式为“如何实现效果X,在我看来,这需要非阻塞操作,而仅使用阻塞操作?”如果您要编写一个单独的问题,其中包含有关效果X的一些详细信息。
旁注:我很想用以下方式写上面的内容,虽然含义相同,但从美学角度来说更吸引我:
watcher = forever (asks drawer >>= liftIO . takeMVar >>= printThing)