Почему моей программе на haskell не хватает памяти? - PullRequest
3 голосов
/ 08 февраля 2012

Здравствуйте, товарищи по программированию. Поэтому я решил переписать некоторые из моих старых сценариев, которые лежали в Хаскеле только потому, что мне нужна практика, и мне нравится язык. Поэтому здесь я пытаюсь отфильтровать огромный файл (около 1,7 ГБ), вырезать ненужные строки и записать оставшиеся файлы в другой файл.

Я думал, что ленивая природа haskell будет идеальной для этого, но коду слишком быстро не хватает памяти. В предыдущих версиях (c # или Python) был подход «строка чтения -> запись строки», но здесь я попробовал другой подход. Должен ли я просто переписать код, чтобы отразить предыдущую версию, или я что-то упустил.

Итак, эта функция отвечает за фильтрацию исходного файла:

getLines :: FilePath -> IO [[String]]
getLines path = do
    text<-readFile path
    let linii=lines text
    let tokens = map words linii
    let filtrate=[x|x<-tokens,length x>7,isTimeStamp (x!!0),isDiagFrame x]
    return filtrate

этот отвечает за запись одной строки за раз в новом файле (хотя я пытался использовать writeFile напрямую и с треском провалился :):

writeLines ::Handle->[[String]]->IO ()
writeLines handle linii = do
                    let linie=concat $ intersperse " " (head  linii)
                    hPutStrLn handle linie
                    if length linii > 0     then
                                    writeLines handle  (tail linii)
                                        else
                                    print "Writing complete..."

и эти 2 являются основной функцией, а другая отвечает за получение ручки и ее передачу:

writeTheFile :: FilePath->FilePath->IO ()
writeTheFile inf outf = do
handle<-openFile outf WriteMode
linii<-getLines inf
writeLines handle linii
print "Write Complete"


main = do
arg<-getArgs
if length arg/=2    then
    print "Use like this : trace_pars [In_File] [Out_File] !"
                    else 
    writeTheFile (arg!!0) (arg!!1)

Любой совет будет принята с благодарностью ... заранее спасибо

1 Ответ

14 голосов
/ 08 февраля 2012

Проблема здесь в этой строке:

                    if length linii > 0     then

Вы вычисляете длину вашего списка строк.Это означает, что весь список строк должен быть загружен для его подсчета.Это означает, что весь файл, который вы читаете, должен быть загружен в память.Не хорошо!

Решение состоит в том, чтобы использовать if not . null $ linii then вместо этого.Функция null проверяет, является ли список пустым (что приводит к загрузке только первой строки списка), и not ведет себя так, как вы ожидаете.

Если вы хотите более идиоматическийверсия writeLines (обратите внимание на использование FilePath вместо Handle):

writeLines :: FilePath -> [[String]] -> IO ()
writeLines filename = writeFile filename . unlines . map unwords

Эта функция аналогична:

writeLines filename lines =
  writeFile filename mergedFile
  where
    mergedFile = unlines mergedLines
    mergedLines = map unwords lines

unlines являетсятакой же, как intercalate "\n", а unwords такой же, как intercalate " ".intercalate x совпадает с concat . intersperse x.

Я думаю, что этой информации должно быть достаточно для того, чтобы вы поняли, что происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...