информирование об ошибках парсинга шло через возвращаемые значения, а не через исключения. Исключения просаживают производительность, а т.к. нужно было парсить приходящие извне данные, то заранее не предугадаешь, с какой частотой ошибки будут возникать;
хотелось имееть более удобный способ получать разобранные значения нежели syntax actions, как в spirit и pegtl;
не было тяжелых зависимостей;
реализация всего этого дела была header-only (т.к. нам нужно было это все в header-only либе использовать).
В итоге сделали свое и не стали брать ни spirit, ни pegtl.
Ещё вот интересно - а вы замеряли просадку в производительности и частоту ошибок в приходящих данных?
Не в этом конкретном случае, но в этом же проекте у нас было так, что по недосмотру начинали выскакивать исключения, тут же ловились и обрабатывались. При этом падение было где-то раз в 10, если не ошибаюсь. Т.е. буквально на бенчмарках показатели падали где-то со 100K req/sec до 10-15K.
Хм, на самом деле да, я чет не подумал про сценарий когда оно в открытой для злоумышленника сети торчит наружу, получается DoS так проще устроить.
Я почему спросил, видел дюже эффективный парсер, но там были использованы исключения. Однако, там типовой сценарий был это во-первых - длительное соединение, во-вторых разрыв соединения после первой ошибки.
Так никакого секрета нет, нам нужно было в RESTinio парсить HTTP-заголовки. По грамматикам из RFC. А уж что в этих заголовках от клиента может прилететь – хз. Могут тупо по недосмотру неправильно значения заголовков формировать и тогда ошибки парсинга будут в 100% случаев.
Вот я тоже в своем проекте взялся сразу за boost.spirit, посмотрел, как на нем получается, а потом сделал свой мини парсер, тем более для моей минимальной грамматики потребовалось три функции.
по недосмотру начинали выскакивать исключения, тут же ловились и обрабатывались. При этом падение было где-то раз в 10, если не ошибаюсь. Т.е. буквально на бенчмарках показатели падали где-то со 100K req/sec до 10-15K
Так это, в плюсах что ли до сих пор невменяемо медленные исключения? Я думал, это уже сто лет в обед как исправили в флагманских компиляторах.
Так это, в плюсах что ли до сих пор невменяемо медленные исключения?
Исключения в C++ сейчас практически zero cost если они не бросаются.
Сам выброс исключения очень дорогой.
Вроде как в Интернетах можно нарыть попытки сравнения производительности, из которых можно сделать вывод о том, что исключения эффективнее кодов возврата, если исключения бросаются в считанных процентах случаев. Если же проблемных ситуаций становится больше 10%, то исключения гарантированно просаживают производительность.
Так что приходится оценивать, насколько часто придется информовать об ошибках. И если часто, то пока что исключения вне игры :(
На самом деле даже если исключения не бросаются, они все равно не zero cost, т.к. в программе приходится хранить таблицу адресов, благодаря которой при выбросе исключения компилятор понимает, куда нужно передавать управление (вроде бы правильно сформулировал).
А с этим можно что-либо сделать, хотя бы в теории, или это фундаментальное свойство самого механизма (вытекающее из необходимых свойств исключений по стандарту)?
Реакция на первую версию предложения была неоднозначная. В частности, многих напряг момент со слишком жестким подходом к невозможности выделения памяти (т.е. terminate вместо bad_alloc). Поэтому в последующих ревизиях этот момент попытались смягчить.
В C++20 не попало. А вот при работе над C++23 это предложение будет рассматриваться. И, вроде бы, по словам Полухина, на этот момент завязано еще и предложение по включению в стандарт типа std::expected. Если примут механизм Саттера для исключений, то особого смысла в std::excepted не будет, т.к. новые исключения и будут чем-то вроде std::expected.
PS. Могу чего-то напутать, т.к. в последний раз к этой теме возвращался где-то год назад.
Ну и что, что приходится хранить таблицу. Она вроде никак не влияет на производительность (сам факт ее наличия).
Да, убеждался на собственном опыте, что if медленнее чем исключения (если конечно исключения используются для исключительных ситуаций). Причем исключения тормозят только если они выпали, а if тормозит как в случаи ошибки, так и при нормальном проходе. Может likely решит частично эту проблему..
Проблема исключений в плюсах (нерешаемая) в том, что исключения должны раскручивать весь стек RAII. А этого говна на стеке навалом, в плюсах оно модно.
Аллокация объекта-исключения в динамической памяти.
Проход в обратном порядке по расположенным выше по стеку блокам catch и поиск совпадения типа в catch с типом брошенного исключения (для чего применяется поиск с использованием механизмов RTTI).
Вот эти две вещи являются наиболее дорогими.
Там же эти таблицы вроде бы содержат готовую информацию о том, до какого места нужно разматывать стек?
Эту таблицу я упомянул для того, чтобы показать, что zero cost – это не в чистом виде zero cost. И что даже если исключения не бросаются, за них все равно приходится платить дополнительными данными в программе.
Сами же эти данные оказывают на производительность косвенное воздействие: т.к. они, скорее всего, будут лежать вне кэша, то потребуется потратить время на то, чтобы таблица с адресами переходов и информация RTTI подгрузилась в кэш. Соответственно, какие-то более полезные данные из кэша уйдут, а потом их нужно будет возвращать обратно.