Анализ больших файлов журналов в Haskell

Предположим, у меня есть несколько файлов размером более 200 МБ, которые я хочу просмотреть. Как бы я сделал это в 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ленивый, он избежит чтения всего файла в память.Но запуск обоих скриптов под valgrindпоказал одинаковое использование памяти для обоих. Так что либо мой сценарий неверен, либо valgrindневерен. Я компилирую скрипты, используя

ghc --make test.hs -prof

Что мне не хватает? Бонусный вопрос: я вижу много упоминаний на SO о том, что отложенный ввод-вывод в Haskell на самом деле плох. Как/зачем мне использовать строгий ввод-вывод?

Обновление:

Похоже, я ошибся в своем прочтении 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 байт максимального резидентства, в которой говорится, что в любой момент мой скрипт использовал 101 КБ памяти. в большинстве. Файл, который я искал, весил 44 МБ. Поэтому я думаю, что вердикт таков: readFileи hGetContentsоба ленивы.

Дополнительный вопрос:

Почему в куче выделено 7 ГБ памяти? Это кажется очень высоким для сценария, который читает файл размером 44 МБ.

Дополнение к последующему вопросу

Похоже, несколько гигабайтов памяти, выделенных в куче, не являются чем-то необычным для Haskell, поэтому нет причин для беспокойства. Использование ByteStringвместо Stringзначительно снижает использование памяти:

  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)

10
задан Vlad the Impala 17 March 2012 в 20:17
поделиться