我尝试解析haskell中的大型日志文件。我使用System.IO.Streams
,但是当我折叠输入时,它似乎吃了很多内存。这里有两个(难看的)例子:haskell io流内存
首先将1M Int
加载到列表中的存储器中。
let l = foldl (\aux p -> p:aux) [] [1..1000000]
return (sum l)
内存消耗很漂亮。 INTS吃3MB和列表需要6MB:
see memory consumption of building list of 1M Int
然后试着用字节串的流相同。我们需要一个丑陋的来回交谈,但我不认为有什么差别
let s = Streams.fromList $ map (B.pack . show) [1..1000000]
l <- s >>=
Streams.map bsToInt >>=
Streams.fold (\aux p -> p:aux) []
return (sum l)
see memory consumption of building a list of Ints from a stream
为什么它需要更多的内存?如果我从文件中读取它会更糟糕。它需要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。
'foldl(\ aux p - > p:aux)[]'并不总是多余的。试着拿20美元foldl(\ aux p - > p:aux)[] [1 ..]'vs'20美元[1 ..]'。 – bennofs
@bennofs你是对的。处理无限列表是有区别的.http://stackoverflow.com/questions/3082324/foldl-versus-foldr-behavior-with-infinite-lists – danidiaz
也许我只是错了,问题来自将int转换为bytestring然后回来。我比较了两种解决方案'foldl(\ aux p - > p:aux)[] $ map(bsToInt。iToBs)[1..1000000]'并且没有转换。如果我有字节串,会出现额外的40Mb。 – halacsy