gpt4 book ai didi

exception - 如何使用 unsafeInterleaveIO 处理异常?

转载 作者:行者123 更新时间:2023-12-04 20:08:26 25 4
gpt4 key购买 nike

假设我要打开一个文件并解析其内容,我想懒惰地这样做:

parseFile :: FilePath -> IO [SomeData]
parseFile path = openBinaryFile path ReadMode >>= parse' where
parse' handle = hIsEOF handle >>= \eof -> do
if eof then hClose handle >> return []
else do
first <- parseFirst handle
rest <- unsafeInterleaveIO $ parse' handle
return (first : rest)

如果整个读取过程没有出现错误,上面的代码就可以了。但是如果抛出异常,就没有机会执行 hClose ,并且 handle 将无法正确关闭。

通常,如果 IO 进程不是惰性的,异常处理可以通过 catch 轻松解决。或 bracket .但是在这种情况下,正常的异常处理方法将导致文件句柄在实际读取过程开始之前关闭。这当然不能接受。

那么释放一些由于懒惰而需要保持在其范围之外的资源的常用方法是什么,就像我正在做的那样,并且仍然确保异常安全?

最佳答案

而不是使用 openBinaryFile , 你可以使用 withBinaryFile :

parseFile :: FilePath -> ([SomeData] -> IO a) -> IO a
parseFile path f = withBinaryFile path ReadMode $ \h -> do
values <- parse' h
f values
where
parse' = ... -- same as now

但是,我强烈建议您考虑改用流式数据库,因为它们旨在处理这种情况并正确处理异常。例如,使用管道,您的代码将类似于:
parseFile :: MonadResource m => FilePath -> Producer m SomeData
parseFile path = bracketP
(openBinaryFile path ReadMode)
hClose
loop
where
loop handle = do
eof <- hIsEOF handle
if eof
then return ()
else parseFirst handle >>= yield >> loop handle

如果你改写你的 parseFirst函数使用导管本身而不是下拉到 Handle API,这个胶水代码会更短,你不会直接绑定(bind)到 Handle ,这使得使用其他数据源和执行测试变得更加容易。

导管教程是 available on the School of Haskell .

更新 我忘记提到的一件事是,虽然问题集中在阻止文件关闭的异常上,但如果您没有完全使用输入,即使是非异常情况也会导致这种情况。例如,如果您的文件有多个记录,并且您只强制评估第一个记录,则在垃圾收集器能够回收句柄之前不会关闭文件。 withBinaryFile 的另一个原因或流式数据库。

关于exception - 如何使用 unsafeInterleaveIO 处理异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22280587/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com