Optimization 如何迫使哈斯克尔放弃';你不能通过测试来存储整个数据吗?

Optimization 如何迫使哈斯克尔放弃';你不能通过测试来存储整个数据吗?,optimization,haskell,compression,ghc,huffman-code,Optimization,Haskell,Compression,Ghc,Huffman Code,为了学术目的,我在haskell上写了一个小的(相对)应用程序。我正在基于这段代码实现一个哈夫曼压缩 这段代码的变体在这里,它使用lazy bytestring。当我实现RLE压缩时,一切都很顺利,因为它一步处理输入流。但是Huffman处理它两次,结果我在内存中存储了一个evaluated bytestring,这对于大文件来说是不好的(但是对于相对较小的文件,它也在堆中分配了太多的空间)。这不仅仅是我的怀疑,因为分析还表明大部分堆被bytestring分配吃掉 我还序列化了文件中的流长度,这

为了学术目的,我在haskell上写了一个小的(相对)应用程序。我正在基于这段代码实现一个哈夫曼压缩

这段代码的变体在这里,它使用lazy bytestring。当我实现RLE压缩时,一切都很顺利,因为它一步处理输入流。但是Huffman处理它两次,结果我在内存中存储了一个evaluated bytestring,这对于大文件来说是不好的(但是对于相对较小的文件,它也在堆中分配了太多的空间)。这不仅仅是我的怀疑,因为分析还表明大部分堆被bytestring分配吃掉

我还序列化了文件中的流长度,这也可能导致在内存中加载完整的bytestring。有没有简单的方法可以说ghc会友善地多次重新评估流?

当(Huffmann-)压缩时,通常的方法是,一次收集概率分布,一次进行实际压缩,因为人们无法回避处理输入两次,将输入分块并分别压缩。虽然这仍然会消耗记忆,但它最多只能消耗一个恒定的量

也就是说,您可能希望了解一下,尽管这不适用于标准输入、套接字和其他不受支持mmap的文件系统支持的文件描述符


在收集概率分布后,您还可以从文件中重新读取bytestring(同样,如果您没有从类似管道的任何地方接收到它),但这仍然会使您的代码在1TB文件上退出。

您可以传递计算bytestring的内容,而不是将bytestring传递给编码器,然后在每次需要时显式重新计算该值

compress :: ST s ByteString -> ST s ByteString
compress makeInput = do
  len      <- (return $!) . ByteString.length =<< makeInput
  codebook <- (return $!) . makeCodebook      =<< makeInput
  return . encode len codebook                =<< makeInput

compressIO :: IO ByteString -> IO ByteString
compressIO m = stToIO (compress (unsafeIOToST m))
compress::ST s ByteString->ST s ByteString
压缩makeInput=do

len只需要一次通过。很好,但实际上我的任务是以两次通过的方式实现Huffman压缩。我之所以选择haskell,是因为我正在努力学习这门语言,而且通常的知识是随着实践而来的。我喜欢你的想法,但我无法实现它,因为类型不匹配的抱怨,这期望
IO ByteString
,但推断为
ST s ByteString
。它发生在一行(=@kravitz Ah,我没有注意到“evaluate”只在IO中工作。我将“evaluate”改为(return$!),它可以在ST.Headsink中运行。如果我传递
Data.ByteString.Lazy.readFile name
来压缩IO是否足够?因为内存消耗仍然很大(10M文件为1.5G)@kravitz应该足够了。如果它仍然使用太多的空间,最好的方法是使用-hd来分析()以了解哪些数据占用内存,使用-hr来了解哪些函数保留数据。@Headsink大多数数据都是块(惰性ByTestRing就是从这些块组成的),保留大部分数据的函数是compress(以您建议的方式编写)