наращивание кучи памяти с помощью xml -роводки parseBytes - PullRequest
1 голос
/ 29 марта 2019

Я анализирую несколько довольно больших XML-файлов с потоковым интерфейсом xml-проводника https://hackage.haskell.org/package/xml-conduit-1.8.0/docs/Text-XML-Stream-Parse.html#v:parseBytes, но я вижу это наращивание памяти (здесь в небольшом тестовом файле):

heap use over time

, где топ-пользователи:

heap blame

Фактические данные не должны занимать столько кучи- если я сериализую и перечитываю, резидентное использование памяти будет здесь в килобайтах по сравнению с мегабайтами.

Минимальный пример, который мне удалось воспроизвести:

{-# LANGUAGE BangPatterns      #-}
{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Control.Monad
import           Control.Monad.IO.Class
import           Data.Conduit
import           Data.Conduit.Binary    (sourceFile)
import qualified Data.Conduit.List      as CL
import           Data.Text              (Text)
import           Text.XML.Stream.Parse

type Y = [(Text, Text)]

main :: IO ()
main = do
  res1 <- runConduitRes $
          sourceFile "test.xml"
          .| Text.XML.Stream.Parse.parseBytes def
          .| parseMain
          .| CL.foldM get []
  print res1

get :: (MonadIO m, Show a) => [a] -> [a] -> m [a]
get acc !vals = do
 liftIO $! print vals           -- this oughta force it?
 return $! take 1 vals ++ acc

parseMain = void $ tagIgnoreAttrs "Period" parseDetails

parseDetails = many parseParam >>= yield

parseParam = tag' "param" parseParamAttrs $ \idAttr -> do
  value <- content
  return (idAttr, value)

parseParamAttrs = do
  idAttr <- requireAttr "id"
  attr "name"
  return idAttr

1 Ответ

0 голосов
/ 29 марта 2019

Если я изменю get, чтобы просто вернуть ["hi"] или что-то еще, я не получу накопление. Таким образом, кажется, что возвращенные тексты сохраняют некоторую ссылку на более крупный текст, в котором они находились (например, нарезка нулевой копии, см. Комментарий на https://hackage.haskell.org/package/text-0.11.2.0/docs/Data-Text.html#g:18), поэтому остальная часть текста не может быть собрана мусором, даже если мы Используем только маленькие детали.

Наше решение - использовать Data.Text.copy для любых атрибутов, которые мы хотим получить:

someattr <- requireAttr "n"
yield (T.copy someattr)

, что позволяет нам анализировать при почти постоянном использовании памяти.

(И мы могли бы рассмотреть возможность использования https://markkarpov.com/post/short-bs-and-text.html#shorttext, если мы хотим сохранить еще больше памяти.)

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