Написал небольшую рабочую тулзу (мобильное приложение): она читает экспорт аналитики, CSV с событиями сессий, около 6 миллионов строк и примерно 300 МБ, и выводит среднюю длительность сессии. Ответ получается правильный. Но на полном файле на моём старом Intel MacBook начинают реветь кулеры, а +RTS -s показывает максимальную резидентность заметно больше гигабайта.
Сначала я написал на foldl, потом заменил на foldl', и пиковая память почти не изменилась. -O2 уже стоит в cabal-файле, тоже никакой реальной разницы.
meanMillis :: [Session] -> Double
meanMillis ss
| n == 0 = 0
| otherwise = fromIntegral total / fromIntegral n
where
(total, n) = foldl' step (0 :: Int, 0 :: Int) ss
step (t, c) s = (t + sessMillis s, c + 1)
и в main:
contents <- readFile (optPath opts)
let sessions = mapMaybe parseLine (drop 1 (lines contents))
Session — обычная запись с String и Int, а фильтр по экрану — просто filter.
Первым делом я подозреваю readFile и lines, поэтому думал про цикл на hGetLine, но пока не пробовал. Не понимаю, почему строгого свёртывания не должно хватать, если файл читается лениво и каждая строка выбрасывается после парсинга. Профилировочная сборка на этой машине жутко медленная, так что я в основном гадаю по цифрам из -s.
Куда на самом деле уходит память?