在搜索可以处理大型(300-1000mb)xml文件的haskell库时,我遇到了hextat。Haskell Wiki中有一个例子声称
-- Process document before handling error, so we get lazy processing.
出于测试目的,我将输出重定向到/dev/null
,并向其抛出一个300mb的文件。内存消耗一直在增加,直到我不得不终止进程。
现在我从process
函数中删除了错误处理:
process :: String -> IO ()
process filename = do
inputText <- L.readFile filename
let (xml, mErr) = parse defaultParseOptions inputText :: (UNode String, Maybe XMLParseError)
hFile <- openFile "/dev/null" WriteMode
L.hPutStr hFile $ format xml
hClose hFile
return ()
因此,该函数现在使用常量内存。为什么错误处理会导致大量内存消耗?
据我所知,xml
和mErr
是在调用parse
之后的两个独立的未赋值的thunk。format xml
是否评估xml
并构建'mErr'的评估树?如果是,有没有一种方法可以在使用常量内存的同时处理错误?
http://www.haskell.org/haskellwiki/Hexpat/
我不能在hexpat上与权威人士交谈,但通常情况下,错误处理会迫使您将整个文件读取到内存中。如果只想在输入中没有任何错误的情况下打印出结果,则需要在生成输出之前读取整个输入。
正如我所说,我真的不知道hextat,但有了xml管道,你可以做一些类似的事情:
try $ runResourceT $ parseFile def inputFile $$ renderBytes def =$ sinkFile outputFile
它将使用恒定内存,如果在处理中出现任何错误,它将抛出一个异常(try
将捕获该异常)。缺点是输出文件可能已损坏。我的猜测是,最好的选择是输出到一个临时文件,在整个过程完成后,将临时文件移动到输出文件。在任何异常情况下,只需删除临时文件即可。