【问题标题】:How to force haskell to don't store whole bytestring?如何强制haskell不存储整个字节串?
【发布时间】:2011-02-16 14:30:47
【问题描述】:

我出于学术目的在 haskell 上编写了一个小型(相对)应用程序。我正在实现 Huffman 压缩,基于此代码 http://www.haskell.org/haskellwiki/Toy_compression_implementations

我的代码变体在这里https://github.com/kravitz/har/blob/a5d221f227c27fd1c5587217a29a169a377521a6/huffman.hs,它使用惰性字节串。当我实现 RLE 压缩时,一切都很顺利,因为它一步处理输入流。但是 Huffman 对其进行了两次处理,结果我在内存中存储了一个评估的字节串,这对大文件不利(但对于相对较小的文件,它也在堆中分配了太多空间)。这不仅是我的怀疑,因为 profiling 还表明大部分堆都被字节串分配吃掉了。

我还序列化了文件中的流长度,它也可能导致完整的字节串加载到内存中。有什么简单的方法可以说 ghc 友善并多次重新评估流?

【问题讨论】:

  • Adaptive Huffman Coding 只需要一次通过。
  • 很好,但实际上我的任务是通过两遍方式实现霍夫曼压缩。我为此选择了haskell,因为我正在努力学习这门语言,并且通常知识伴随着实践。

标签: optimization haskell compression ghc huffman-code


【解决方案1】:

您可以传递一些计算字节串的东西,然后在每次需要时显式地重新计算该值,而不是将字节串传递给编码器。

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 的参数实际上应该计算值。简单地用return 包装一个值是行不通的。此外,对makeInput 的每次调用都必须对其结果进行实际评估,否则在重新计算输入时,内存中将保留一个惰性的、未评估的输入副本。

正如 barsoap 所说,通常的方法是一次只压缩一个块。

【讨论】:

  • 我喜欢你的想法,但由于类型不匹配的抱怨,我无法实现它,预期为IO ByteString,但推断为ST s ByteString。它发生在带有 (=
  • @kravitz 啊,我没有注意到“评估”只适用于 IO。我将“评估”更改为(返回 $!),它可以在 ST 中运行。
  • @Heatsink 如果我通过 Data.ByteString.Lazy.readFile name 来压缩 IO 就足够了吗?因为内存消耗还是很大的(10M文件1.5G)
  • @kravitz 这应该足够了。如果它仍然使用太多空间,最好的方法是使用 -hd 分析 (haskell.org/ghc/docs/latest/html/users_guide/prof-heap.html) 以了解哪些数据正在占用内存,并使用 -hr 了解哪些功能正在保留数据。
  • @Heatsink 大部分数据是块(惰性字节字符串从中组成),保留大部分数据的函数是压缩(以您建议的相同方式编写)
【解决方案2】:

(Huffmann-)压缩时的常用方法,因为无法绕过两次处理输入,一次收集概率分布,一次进行实际压缩,是将输入分块并压缩每个分开。虽然这仍然会消耗内存,但它只会最大程度地消耗恒定量。

也就是说,您可能想看看bytestring-mmap,但它不适用于标准输入、套接字和其他不受支持 mmap 的文件系统支持的文件描述符。

在收集概率分布后,您还可以从文件中重新读取字节串(同样,前提是您没有从任何类似管道的地方接收它),但这仍然会使您的代码脱离 1TB 文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-09
    • 2018-08-07
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多