我尝试在 haskell 中解析大型日志文件。我正在使用System.IO.Streams
,但是当我折叠输入时,它似乎占用了很多内存。这是两个(丑陋的)示例:
首先将 1M 加载Int
到列表中的内存中。
let l = foldl (\aux p -> p:aux) [] [1..1000000]
return (sum l)
内存消耗很漂亮。Ints 吃 3Mb,而列表需要 6Mb:
然后对 ByteStrings 流进行同样的尝试。我们需要一个丑陋的来回对话,但我认为没有任何区别
let s = Streams.fromList $ map (B.pack . show) [1..1000000]
l <- s >>=
Streams.map bsToInt >>=
Streams.fold (\aux p -> p:aux) []
return (sum l)
为什么需要更多内存?如果我从文件中读取它,情况会更糟。它需要 90Mb
result <- withFileAsInput file load
putStrLn $ "loaded " ++ show result
where load is = do
l <- Streams.lines is >>=
Streams.map bsToInt >>=
Streams.fold (\aux p -> p:aux) []
return (sum l)
我的假设是 Streams.fold 有一些问题。因为库的内置 countInput 方法不使用它。任何想法?
编辑
经过调查,我将问题简化为:为什么这段代码需要额外的 50Mb?
do
let l = map (Builder.toLazyByteString . intDec ) [1..1000000]
let l2 = map (fst . fromJust . B.readInt) l
return (foldl' (\aux p -> p:aux) [] l2)
没有转换它只需要 30Mb,转换 90Mb。