gpt4 book ai didi

haskell - 在 Haskell 中解析大型日志文件

转载 作者:行者123 更新时间:2023-12-04 03:30:04 25 4
gpt4 key购买 nike

假设我有几个 200mb+ 的文件要通过 grep。我将如何在 Haskell 中执行此操作?

这是我的初始程序:

import Data.List
import Control.Monad
import System.IO
import System.Environment

main = do
filename <- liftM head getArgs
contents <- liftM lines $ readFile filename
putStrLn . unlines . filter (isPrefixOf "import") $ contents

这会在解析之前将整个文件读入内存。
然后我就这样做了:
import Data.List
import Control.Monad
import System.IO
import System.Environment

main = do
filename <- liftM head getArgs
file <- (openFile filename ReadMode)
contents <- liftM lines $ hGetContents file
putStrLn . unlines . filter (isPrefixOf "import") $ contents

我想自从 hGetContents很懒, it will avoid reading the whole file into memory .但是在 valgrind 下运行这两个脚本两者的内存使用情况相似。所以要么我的脚本错了,要么 valgrind是错的。我使用编译脚本
ghc --make test.hs -prof

我错过了什么?额外的问题:我看到很多关于 Haskell 中的 Lazy IO 实际上是一件坏事的提及。我如何/为什么要使用严格的 IO?

更新:

所以看起来我在阅读 valgrind 时错了。使用 +RTS -s ,这就是我得到的:
 7,807,461,968 bytes allocated in the heap
1,563,351,416 bytes copied during GC
101,888 bytes maximum residency (1150 sample(s))
45,576 bytes maximum slop
2 MB total memory in use (0 MB lost due to fragmentation)

Generation 0: 13739 collections, 0 parallel, 2.91s, 2.95s elapsed
Generation 1: 1150 collections, 0 parallel, 0.18s, 0.18s elapsed

INIT time 0.00s ( 0.00s elapsed)
MUT time 2.07s ( 2.28s elapsed)
GC time 3.09s ( 3.13s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 5.16s ( 5.41s elapsed)

重要的一行是 101,888 bytes maximum residency ,这表示在任何给定点我的脚本最多使用 101 kb 的内存。我正在浏览的文件是 44 mb。所以我认为判决是: readFilehGetContents都是懒惰的。

追问:

为什么我看到堆上分配了 7gb 的内存?对于在 44 mb 文件中读取的脚本来说,这似乎真的很高。

更新后续问题

看起来在堆上分配的几 GB 内存对于 Haskell 来说并不典型,因此无需担心。使用 ByteString s 而不是 String s 大大降低了内存使用量:
  81,617,024 bytes allocated in the heap
35,072 bytes copied during GC
78,832 bytes maximum residency (1 sample(s))
26,960 bytes maximum slop
2 MB total memory in use (0 MB lost due to fragmentation)

最佳答案

请不要使用 String s(尤其是在处理 >100 Mb 文件时)。
只需将它们替换为 ByteString s(或 Data.Text):

{-# LANGUAGE OverloadedStrings #-}

import Control.Monad
import System.Environment
import qualified Data.ByteString.Lazy.Char8 as B

main = do
filename <- liftM getArgs
contents <- liftM B.lines $ B.readFile filename
B.putStrLn . B.unlines . filter (B.isPrefixOf "import") $ contents

我敢打赌,这会快几倍。

更新:关于您的后续问题。
切换到字节串时,分配的内存量与魔法加速密切相关。
String只是一个通用列表,它需要为每个 Char 提供额外的内存: 指向下一个元素、对象头等的指针。所有这些内存都需要分配然后收集回来。这需要大量的计算能力。
在另一边, ByteString是一个 block 列表,即连续的内存块(我认为,每个不少于 64 字节)。这大大减少了分配和收集的数量,也提高了缓存的局部性。

关于haskell - 在 Haskell 中解析大型日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9746352/

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