haskell - 惰性数据类型的内存使用情况

标签 haskell memory vector lazy-evaluation

我编写了一个程序,用于分析文件中的数据并对其执行操作。我的第一个实现使用 Data.ByteString 来读取文件的内容。然后使用Data.Vector.Unboxed将此内容转换为样本向量。然后,我对这个(未装箱的)样本值向量执行处理和分析。

作为一个实验,我想知道如果我利用 Haskell 的惰性会发生什么。我决定使用 Data.ByteString.Lazy 而不是 Data.ByteStringData.Vector 而不是 Data 来进行这个简单的测试.Vector.Unboxed。我期望看到内存使用情况有所改善。即使我的程序最终需要知道每个样本的值,我仍然期望内存使用量会逐渐增加。当我分析我的程序时,结果令我惊讶。

我的原始版本在大约 20 毫秒内完成,其内存使用情况如下: enter image description here 在我看来,这似乎是一种懒惰的行为。示例似乎已加载到内存中,因为我的程序需要它们。

使用 Data.VectorData.ByteString 得到以下结果: enter image description here 这看起来与懒惰行为相反。所有样本似乎都被一次性加载到内存中,然后一一删除。

我怀疑这与我对 Boxed 和 Unboxed 类型的误解有关,因此我尝试使用 Data.ByteString.Lazy 与“数据.矢量.未装箱”。结果是这样的: enter image description here 我不知道如何解释我在这里所看到的。

谁能解释一下我得到的结果吗?

编辑 我正在使用 hGet 读取文件,这给了我一个 Data.ByteString.Lazy。我通过以下函数将此 ByteString 转换为 float 的 Data.Vector:

toVector :: ByteString -> Vector Float
toVector bs =  U.generate (BS.length bs `div` 3) $ \i ->
     myToFloat [BS.index bs (3*i), BS.index bs (3*i+1), BS.index bs (3*i+2)]
  where
    myToFloat :: [Word8] -> Float
    myToFloat words = ...

float 用 3 个字节表示。

其余的处理主要包括对数据应用高阶函数(例如filtermap等)。

编辑2 我的解析器包含一个函数,该函数从文件中读取所有数据并以样本向量返回该数据(使用之前的 toVector 函数)。我编写了该程序的两个版本,一种使用 Data.ByteString,另一种使用 Data.ByteString.Lazy。我使用这两个版本进行了简单的测试:

main = do
  [file] <- getArgs
  samples <- getSamplesFromFile file
  let slice = V.slice 0 100000 samples
  let filtered = V.filter (>0) slice
  print filtered

严格版本给出了以下内存使用情况: enter image description here 惰性版本给了我以下内存使用情况: enter image description here 这个结果似乎与我的预期完全相反。有人可以解释一下吗? Data.ByteString.Lazy 有什么问题吗?

最佳答案

您正在惰性字节字符串上使用length。这将需要整个字符串。如果这是输入惰性字节串的唯一用途,则垃圾收集可以使其在常量空间中工作。但是,您随后访问该字符串以进行进一步计算,从而强制整个数据保留在内存中。

解决这个问题的方法是完全避免length,并尝试折叠惰性字节串(仅一次!),以便流式传输可以完成其工作。

例如,您可以执行类似的操作

myread :: ByteString -> [Float]
myread bs = case splitAt 3 bs of
   ([x1,x2,x3], end) -> myToFloat x1 x2 x3 : myread end
   -- TODO handle shorter data as well

toVector bs = U.fromList $ myread bs

可能有更好的方法来利用 Vector 内容。 U.unfoldr 看起来很有前途。

关于haskell - 惰性数据类型的内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42319163/

相关文章:

Haskell 的图像绘图库?

haskell - 让 5 = 10 做什么?这不是赋值操作吗?

haskell - Julia 是否有类似于 Haskell 的美元符号的运算符?

c++ - 使用 getline 拆分字符串并检查 int

haskell - UndecidableInstances 何时安全?关于 GHC 扩展的一些一般性问题

windows - 如何从剪贴板内存 (uintptr) 中检索图像数据缓冲区?

c - 如何在 C 中跟踪动态分配的内存

Android:由于 AsyncTask 导致内存泄漏

reflection - 2D 游戏 - 如何反射球棒上的球?

r - 检查 R 向量中的序列