我一直在尝试使用Haskell读取大文件。
我需要使用自定义算法对其进行压缩,这是一个大学项目。一切都很顺利,直到我开始压缩大文件。
我从程序中找出了问题,并以“大文件你好”的形式展示出来:
import System
import qualified Data.ByteString.Lazy as BL
import Data.Word
fold_tailrec :: (a -> b -> a) -> a -> [b] -> a
fold_tailrec _ acc [] =
acc
fold_tailrec foldFun acc (x : xs) =
fold_tailrec foldFun (foldFun acc x) xs
fold_tailrec' :: (a -> b -> a) -> a -> [b] -> a
fold_tailrec' _ acc [] =
acc
fold_tailrec' foldFun acc (x : xs) =
let forceEval = fold_tailrec' foldFun (foldFun acc x) xs in
seq forceEval forceEval
main :: IO ()
main =
do
args <- System.getArgs
let filename = head args
byteString <- BL.readFile filename
let wordsList = BL.unpack byteString
-- wordsList is supposed to be lazy (bufferized)
let bytesCount = fold_tailrec (\acc word -> acc + 1) 0 wordsList
print ("Total bytes in " ++ filename ++ ": "
++ (show bytesCount))
我将这个文件命名为Test.hs,然后按照以下步骤操作:
$ ls -l toto
-rwxrwxrwx 1 root root 5455108 2011-03-23 19:08 toto
$ ghc --make -O Test.hs
[1 of 1] Compiling Main ( Test.hs, Test.o )
Linking Test ...
$ ./Test toto
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
$ ./Test toto +RTS -K50M -RTS
Stack space overflow: current size 50000000 bytes.
Use `+RTS -Ksize -RTS' to increase it.
$ ./Test toto +RTS -K500M -RTS
"Total bytes in toto: 5455108"
$ time ./Test toto +RTS -K500M -RTS
"Total bytes in toto: 5455108"
real 0m33.453s
user 0m8.917s
sys 0m10.433s
请问为什么我需要500兆字节的RAM和30秒的CPU时间才能浏览一个区区5兆字节的文件?请问我做错了什么?为什么[word8]没有像ByteString文档所说的那样被缓存?该如何解决?我尝试使用自己定义的尾递归函数来代替foldl、foldr或foldl',并尝试使用seq来取消挂起的thunks,但目前还没有结果。
感谢任何帮助,因为我卡住了。
stat(2)
向操作系统询问并保存所有磁盘IO。 - sarnoldlength
会导致内存泄漏。你必须将整个东西保留在内存中,因为在调用length
之前它无法进行垃圾回收。 - Ezralength [1..100000000]
这样的东西,它将在 O(1) 的时间内完成,因为 Haskell 可以在 length 迭代列表时垃圾回收字符串的开头。只有在之后再次使用列表时才会出现问题。 - fuz