• XML sax Haskell XML SAX Parser.
    Lazy ByteString хорошо, но долго.
    Добавляем туда замечательных фолдов, просто считаем число событий, максимально не ленясь. Для начала.
    Итого 1035 секунд на 3.5 ГБ.
    Strict ByteString хорошо, но сразу не хватает памяти.
    Думаю, раз такое дело, то стоит дробить Strict ByteString на куски определенного размера +- несколько десятков байт на то, чтобы гарантированно попасть на границу событий. И затем передавать вычисленный аккумулятор дальше по списку.
    Думаю, так оно быстрее выйдет.
    ♡ recommended by @ndtimofeev, @thefish

Replies (44)

  • @agr, Расскажи потом что из этого вышло. XML это самое больное место Haskell'я.
  • @agr, Ленивый байтстринг это и есть дробленый строгий.
  • @agr, подписалсо
  • @agr, LBS это список Strict BS, можно поверх какой интеративной либы
  • @qnikst, Исторически сложилось: tagsoup, fast-tagsoup.

    tagsoup: StringLike str, но!
    — раз! hackage.haskell.org
    — два! hackage.haskell.org

    fast-tagsoup: только так..
    hackage.haskell.org
  • @agr, fast-tagsoup отжирает всю память и ему ещё подавай.
  • @ndtimofeev, Договорились.

    В идеале мне нужно достичь скорости из описания к fast-tagsoup, которую нарисовал там @shabanov.
  • @agr, печалька так, если бы fast-tagsoup, говорил бы где парсить закончил.. Хотя посмотри, какой там последний тег вылезает, может с ошибой, тогда в принципе можно выкрутиться и научить его lbs (хотя попределенная часть скорости на этом потеряется
  • @agr, Промежуточный результат такой.
    При попытке дробить ByteString на куски размером ~10 млн байт, через пару минут происходит падение вида:

    hGetBuf: invalid argument (Invalid Argument)

    5 лет назад рекомендовали переходить на Lazy... mail.haskell.org
  • @agr, lazy делает то, что ты хочешь автоматом, а строгие тут исключительно из-за проблем апи либы :(
  • @qnikst, hGetBuf invalid argument это что-то странное в данном случае, ты там точно хэндл раньше времени не закрываешь?
  • @qnikst, Честно говоря, я тупо делаю B.readFile.
    Сейчас попробую с хэндлом.
  • @agr, B.readFile а что тогда дробишь?
  • @qnikst,
    content <- B.readFile file

    content и дроблю далее.
  • @agr, можно toChunks сразу, там размер может быть мелковат правда
  • @qnikst, Сейчас его попробую.
  • @agr, я правда не знаю, чего с этого толку, т.к. fast-tagsoup не расскажет, где остановился с разбором
  • @agr, И какой в этом смысл? Памяти ты так не сэкономишь.
  • @qnikst, а хотя cdata он все равно не умеет, так что можно найти халявное решение
  • @qnikst, да, toChunks будет гарантированно рвать события, а мне надо резать строку на куски на границах "событий".
  • @agr, в общем, натравливаю свой нарезчик на Lazy ByteString, а куски в toStrict и на конвейер.
  • @agr, В общем, такой подход сработал.
    Прирост скорости в 11.5 раз.
    Тот же объём данных прошуршал за 88 секунд.
    Т.е. скорость обработки достигла примерно 30 Mbps.
  • @agr, Увеличил размер рукотворного чанка до ~50 млн байт.
    Прирост скорости в ~15 раз.
    200 МБ ОЗУ.
    72 секунды.

    Тест пройден.
  • @rkit, Тут же лень.. Непосредственное чтение будет осуществляться в итераторе, где уже сработает foldl' с принудительным расчётом аккумулятора.

    Почитали чанк — отдали его парсить.
    Почитали другой чанк — отдали парсить.
  • @agr, Кстати, это наводит на мысль о многопоточности.
    Что если слегонца отделить дробление файла и парсинг и разнести их по разным тредам?!
  • @agr, дык поток то данных всё равно с диска читается, быстрее чем читается не обработаешь
  • @dr-Chaos, пока парсится предыдущий кусок, нарезается следующий
    парсер допарсил — ждёт нарезку

    я про это
  • @agr, парсер работает быстрее чтения с диска или медленнее? Чтение с диска идёт в процессе нарезки?
  • @dr-Chaos, 1. Не знаю пока.
    2. Да, идея сделать так.
  • @agr, понимаешь, если ты читать параллельно не сможешь, то ожидание будет не на чтении из файла, а на очереди сообщений. Если читается быстро, то можно очередь разбирать несколькими потоками парсерами, но тогда надо ещё будет и собирать результат.
    Т.е. по скорости, как мне кажется, выигрыша не будет. Однако, архитектурно ты отделишь парсер от читалки нарезки и сможешь легко заменить чтение из файла, чтением по сети, etc. Возможно тогда лучше a la conduit интерфейс?
  • @dr-Chaos, Хм.. Да, согласен.

    Либо ввязываться в это мероприятие, либо остановиться на текущем результате и сделать второй тест, на более сложном аккумуляторе, близком к требуемой задаче.
  • @agr, Второй тест на генерацию перечня уникальных XPath (без учёта атрибутов) пройден за 268 секунд при 400 МБ ОЗУ.
  • @agr, жги! давай!
  • @dr-Chaos, Тут на самом деле момент такой:
    — есть магическое число, 50 млн.
    — на разных машинах конфигурации железок разные.
    т.е. где-то 400 МБ (на фоне остального барахла) — много, где-то — мало.
    вопрос в том, чтобы вычислять свободную память в системе, по этому значению определять "магическое" число, т.е. задекларировать магию.
  • @agr, Да, время выполнения тоже будет меняться, но это уже допустимо.
  • @agr, Залип на третьем тесте. С поддержкой атрибутов.
  • @agr, Блин забыл про контроль памяти отписаться в принципе с точностью до атрибутов там все можно зопилить, надо бы как-нить поиграться
  • @agr, а почему таки HXT?
  • @qnikst, Вот как раз игрался с ними. Но, кажется, доигрался..
    С понедельника приоритет проекта понижается, к сожалению.
  • @alar, Не, не HXT. Под капотом всё те же tagsoup или hexpat (речь о SAX парсере, DOM не катит в принципе). От последнего отказался в своё время, медленный, см. графики отсюда: wiki.haskell.org
  • @agr, чего бы такого принять, чтобы тагсуп не казался стрёмным бессистемным поделием? Потому что объективно мне надо его освоить.
  • @alar, Посмотреть на SAX парсер в xml-conduit
  • @qnikst, В общем, порассматривал код, в соответствии с #2810110/8.
    В результате ошибка крылась в функции, которая трансформировала аккумулятор. Как избавился от лишних телодвижений — отлегло сразу.

    Третий тест: получения уникального списка XPath с учётом атрибутов:
    257 секунд, в пике 400 МБ ОЗУ.
  • @agr, Теперь попробую усложнить аккумулятор до четвёртого теста.
    Но подробностей раскрыть не смогу, к сожалению.

    Всем спасибо за поддержку.