Haskell, Parsec 2 и тормоза

Apr 26, 2010 01:14

Помня о том, какое бурление вызвало сравнение скорости Лиспа с другими языками в прошлом номере ПФП, прошу помощи зала не допустить несправедливости. Я сейчас доделываю сравнение скорости разных методов парсинга, сделал вариант на Хаскеле на базе Parsec2, и получившаяся скорость мне совсем не нравится. До этого на Хаскеле не писал, поэтому ( Read more... )

haskell, fp, parsers

Leave a comment

Comments 41

anonymous April 25 2010, 19:10:37 UTC
А какие реализации будут сравниваться? Boost.Spirit будет?

Reply

thedeemon April 25 2010, 19:29:26 UTC
Я очень хотел бы сравнить и с ним тоже. Но варианта решения на нем у меня пока еще нет. Если поможете - буду очень благодарен!

Сейчас готовы цифры по таким вариантам:
OcamlYacc, классические парсер-комбинаторы на Окамле, их модификация без списков, оптимизирующие парсер-комбинаторы на Окамле (это тема статьи), C#/System.Xml, Haskell/Parsec2.
Планируется еще добавить Boost.Spirit. Если есть еще предложения - буду рад услышать.

Reply

alexott May 3 2010, 10:54:45 UTC
только бери 2-й спирит, он сильно быстрее

Reply

thedeemon May 5 2010, 07:57:38 UTC

justy_tylor April 25 2010, 19:29:44 UTC
Лет семь назад Parsec был такой же прикольный и медленный. Для излечения его патчили под применение других типов (вместо String, который [Char]). В Parsec 3 вроде что-то иное, не смотрел. А мне советовали использовать Happy - чему разумеется не последовал, меня интересовала система описания грамматик, а не использование Хаскеля для production.

Reply

thedeemon April 25 2010, 19:35:10 UTC
Я когда эту тему обсуждал с организаторами, мне рекомендовали из Парсеков брать именно второй, т.к. третий медленнее.

Reply

lionet April 26 2010, 01:06:30 UTC
Happy/Alex на bytestring'fх примерно в три раза медленнее, чем ocamlyacc/ocamllex на парсинге JSON'а.

Reply

thedeemon April 26 2010, 03:33:25 UTC
Здесь Парсек вчетверо медленнее ocamlyacc'a, т.е. разница по скорости с Happy невелика, похоже. Об этом adept тоже упоминал.

Reply


sleepy_drago April 26 2010, 07:22:18 UTC
да библиотечные строки грустные совсем. собрал у себя и запустил ~4 сек. Для сравнения http://code.google.com/p/pugixml/ считывает в DOM и выполняет обход с выводом имени каждого узла в cout за 0.2 сек

Reply

nealar April 26 2010, 09:13:45 UTC
Некорректное сравнение. Если сравнивать готовый XML-парсер, то не с парсечной реализацией, а с готовым XML-парсером.

Reply

sleepy_drago April 26 2010, 13:03:27 UTC
разумеется некорректно тк потоковый парсер будет существенно быстрее :) Я просто провел baseline - для перформанса. Там строится полный DOM (это тормоз номер раз) и для каждого нода делается 1 strcmp и 2 atof (это тормоз номер два тк парсер имеет это значение быстрее).

Вот собсно код http://www.everfall.com/paste/id.php?br3cu0ui8ere
(61 строка). Собиралось 10м экспрессом (в пустой проект добавить этот файл и все 4 файлика пуги. Время работы релиза со статикой ~0.17 сек. Результат практически такой же ( другая точность распечатки плавучки ) и я поленился на мессаджи :)

Reply

nealar April 26 2010, 16:23:53 UTC
Да, я тоже думаю, что HaXml будет медленней. Тем не менее, либу их коробки, разбирающую ДОМ, корректно сравнивать с ним. А наколенник на bison - с наколенником на Happy, в крайнем случае на парсеке.

Reply


potan April 26 2010, 07:51:17 UTC
Да, Parsec не быстрый. И еще ленивость может сюрприз преподнести - скорость работы может зависеть от того, что потом с результатом делается.

Кстати, в Haskell можно работать со структурами аналогично OCaml:

update_lat lat bnd = bnd {
minlat = min lat (minlat bnd),
maxlat = max lat (maxlat bnd)
}

Reply

thedeemon April 26 2010, 08:11:10 UTC
Результат (состояние парсера после окончания его работы) выводится на экран, ответ совпадает с остальными методами, т.е. файл парсится целиком, сюрпризов пока не видно.

Про структуры спасибо за хинт, поправлю.

Reply


potan April 26 2010, 07:55:18 UTC
Да, еще можно попробовать лишние try убрать. Из-за них (опять таки в связи с ленивостью) может заметно тормозить.

Reply

thedeemon April 26 2010, 08:13:19 UTC
А которые там лишние?
Документация говорит, что комбинатор альтернативы не делает сам откат в случае неудачи первого варианта, а для корректной работы откаты эти нужны, поэтому я в непоследние альтернативы повставлял try.

Reply

potan April 26 2010, 08:40:25 UTC
Ну там где откат не должен происходить. Думаю что большенство :-).
Проблема в том, что в ленивом языке комбинатор, аналогичный <|>, в случае удачи с первой альтернативой должен идти дальше и возвращаться к следующими альтернативам в случаях обломов. Для этого он должен все помнить. Что бы избежать этой проблемы, <|> находит первый сработавший парсер и забывает про остальные.
"Идеологически правильное" поведение можно востановить с помощью try (как именно уже не помню), но нужно это сравнительно редко.

Reply

thedeemon April 26 2010, 09:01:55 UTC
Нипанятна.
Возьмем простой пример. Файл состоит из XML тэгов, тэг может быть node, а может быть какой-то другой, нам не интересный. Сейчас это описано как
try p_node <|> p_tag
Если убрать try, то парсер попробует разобрать очередной тэг как node, и если не получилось, то с _текущей_ позиции будет пытаться разбирать tag, но часть символов (как минимум открывающая скобка) уже будет съедена, что приведет к ошибке. Т.е. нужно вернуться на начало тэга, для этого и try. Или я все неправильно понял?

По идее, try можно убрать из тех мест, где начала альтернатив точно не пересекаются, например при разборе флоатов. Попробую.

Reply


Leave a comment

Up