gpt4 book ai didi

Haskell ByteStrings - 最终将大文件加载到内存中

转载 作者:行者123 更新时间:2023-12-04 20:23:16 24 4
gpt4 key购买 nike

问候,

我试图理解为什么我看到整个文件使用以下程序加载到内存中,但是如果您注释掉“(***)”下面的行,那么程序会在恒定(大约 1.5M)空间中运行。

编辑:该文件大约 660MB,第 26 列中的字段是一个日期字符串,如“2009-10-01”,并且有 100 万行。该过程在到达“getLine”时使用了大约 810MB

我是否认为它与使用“split”拆分字符串有关,并且以某种方式从文件中读取的底层 ByteString 不能被垃圾收集,因为它仍然被引用?但如果是这样,那么我认为 BS.copy 会解决这个问题。任何如何强制计算的想法 - 我似乎无法将“seq”放入正确的位置以产生效果。

(注意源文件是制表符分隔的行)

提前致谢,

凯文

module Main where

import System.IO
import qualified Data.ByteString.Lazy.Char8 as BS
import Control.Monad


type Record = BS.ByteString

importRecords :: String -> IO [Record]
importRecords filename = do
liftM (map importRecord.BS.lines) (BS.readFile filename)

importRecord :: BS.ByteString -> Record
importRecord txt = r
where
r = getField 26
getField f = BS.copy $ ((BS.split '\t' txt) !! f)

loopInput :: [Record] -> IO ()
loopInput jrs = do
putStrLn $ "Done" ++ (show $ last jrs)
hFlush stdout
x <- getLine
return ()

-- (***)
loopInput jrs

main = do
jrs <- importRecords "c:\\downloads\\lcg1m.txt"
loopInput jrs

最佳答案

您调用last强制列表,jrs .要弄清楚这一点,它必须遍历整个文件,为 jrs 中的每个条目构建 thunk。 .因为您没有评估 jrs 中的每个元素(除了最后一个)这些 thunk 与对字节串的引用一起挂起,因此必须保留在内存中。

解决方案是强制评估这些 thunk。因为我们谈论的是空间,所以我做的第一件事实际上是以较小的格式存储您的信息:

type Year   = Word16
type Month = Word8
type Day = Word8
data Record = Rec {-# UNPACK #-} !Year {-# UNPACK #-} !Month {-# UNPACK #-} !Day
deriving (Eq, Ord, Show, Read)

这将丑陋的 10 字节字节串(+ 约 16 字节结构信息的开销)减少到大约 8 字节。
importRecord现在必须调用 toRecord r获得正确的类型:
toRecord :: BS.ByteString -> Record
toRecord bs =
case BS.splitWith (== '-') bs of
(y:m:d:[]) -> Rec (rup y) (rup m) (rup d)
_ -> Rec 0 0 0

rup :: (Read a) => BS.ByteString -> a
rup = read . BS.unpack

当我们从 ByteString 转换时,我们需要评估数据至 Record ,所以让我们使用 parallelDeepSeq 打包并定义一个 NFData 实例.
instance NFData Record where
rnf (Rec y m d) = y `seq` m `seq` d `seq` ()

现在我们准备好了,我将 main 修改为使用 evalList ,从而在想要最后一个的函数之前强制执行整个列表:
main = do
jrs <- importRecords "./tabLines"
let jrs' = using jrs (evalList rdeepseq)
loopInput jrs'

我们可以看到堆配置文件看起来很漂亮( top 同意,程序使用的内存非常少)。

alt text

对不起,其他误导性的错误答案 - 我被增量处理修复它的事实迷住了,并没有真正意识到 thunk 真的在附近徘徊,不知道为什么我的大脑滑过那个。尽管我确实坚持要点,但您应该逐步处理这些信息,使所有这些答案变得毫无意义。

仅供引用,巨大的字节串没有出现在我之前发布的那些堆配置文件中,因为堆分析器没有跟踪外部分配(包括 ByteString )。

关于Haskell ByteStrings - 最终将大文件加载到内存中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3962659/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com