LINUX.ORG.RU

Исключения должны работать медленно?

 


1

3

Допустим у меня в контексте 100500 объектов. Внезапно возникает исключение и мы должны покинуть контекст. Начинают работать 100500 деструкторов. Некоторые работают очень медленно, например закрывают соединения с клиентов. Таким образом получается, что с момента возникновения исключения до начала его обработки в другом контексте могут проходить секунды. А мне это не надо. Как запретить выполнение деструкторов для определенных классов?


не надо писать такие деструкторы

Harald ★★★★★
()

Надо либо использовать исключения для исключительных ситуаций (или вообще забыть поо них, как про страшный сон), либо переходить на язык с GC

annulen ★★★★★
()

нет

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

zendrz ★★
()
Последнее исправление: zendrz (всего исправлений: 1)

исключения работают медленно везде, но в языках со сборщиками мусора деструкторы вызываются позже, поэтому кажется, что исключения работаю быстро.

да, они должны работать медленно.

Как запретить выполнение деструкторов для определенных классов?

  1. поймать исключение раньше, а не раскручивать весь стек 2) не выбрасывать исключения 3) отправлять объекты в сборщик мусора, а не уничтожать сразу
anonymous
()

Исключения должны быть «исключительными». На то и рассчитан весь механизм.

dave ★★★★★
()

Если прямо сильно надо, то можно проверять идёт ли сейчас раскрутка стека.

xaizek ★★★★★
()
Ответ на: комментарий от zendrz

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

Lzzz
() автор топика
Ответ на: комментарий от andalevor

наоборот. их не надо перехватывать, тогда выбрасывание исключения будет эквивалентно вызову std::abort, деструкторы не вызовутся.

anonymous
()

А мне это не надо.

А что тебе надо? Если контекст покинуть все равно нужно, и если освободить ресурсы занятые объектами все равно необходимо, то какие у тебя еще есть варианты?

А вообще, если у тебя обработка исключения выкинутого в одном контексте происходит в другом, то либо ты не понимаешь значение слова «контекст», либо тебе надо всю программу немедленно удалять и писать заново.

anonymous
()
Ответ на: комментарий от Lzzz

будет вызов std::abort: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html

In addition, for every object derived from class exception, there exists a corresponding function with C language linkage. An example:

#if __cpp_exceptions
  void __throw_bad_exception(void)
  { throw bad_exception(); }
#else
  void __throw_bad_exception(void)
  { abort(); }
#endif
anonymous
()
Ответ на: комментарий от anonymous

Нормально. Вряд ли нужно продолжать работу после исключения в системной либе.

Lzzz
() автор топика

Исключения должны работать медленно?

Как запретить выполнение деструкторов для определенных классов?

Виноваты бабы деструкторы, но мужики исключения должны.

anonymous
()

1. Исключения работают быстро. Очень быстро, даже быстрее логики на if. Пруф.

2. У тебя проблема в логике программы.

Деструктор должен вызваться всегда, когда он должен вызываться. Например, если у тебя локальная переменная-объект в функции, то при выходе из функции должен вызываться ее деструктор; и не важно, это return или throw. И это правильно.

Но вот в деструкторах, ты, скорее всего делаешь слишком много.

Я бы перепроверил бы что так много занимает времени. Если это соединения с клиентом - может не нужно их так часто открывать/закрывать? Может закрывать более жестко, как сделала бы ОС, если программу убить по kill -9? Если нет - может вынести логику открытия/закрытия соединения в глобальный объект «controller», который бы работал в отдельном треде, или завершал всё в какой-то другой точке программы, куда не так часто долетают исключения (да, это аналог сборщика мусора).

Если ты рассматриваешь вариант с «отключением исключений», значит без них можно обойтись (в смысле совсем обойтись, даже без if), значит у тебе в программе «логика на исключениях», что плохо.

Мне выгодней упасть и перезапуститься пусть ОС сама освобождает все ресурсы, чем ждать когда отработают все деструкторы.

Значит в деструкторах ты делаешь что-то лишнее.

Мне выгодней упасть и перезапуститься

Вот и родился еще один антипаттерн.
Сейчас пойдет поколение программ, которые опираются на авто-хилинги. (Продолжать не буду, остались одни нецензурные слова).

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 3)
Ответ на: комментарий от Kroz

в глобальный объект «controller»

А как синхронизовать время жизни объекта и этого глобального контроллера? Нужно копировать все указатели на выделенные ресурсы? В книгах написано, что в raii лучшее место для освобождение это деструктор.

Lzzz
() автор топика
Ответ на: комментарий от Kroz

одни нецензурные слова

В erlang именно так и работает, немного изучала. Никаких обработок ошибок, процесс упал, перезапустили и летят дальше. Думаю, что в 99% исключений лучше всего упасть и перезапуститься, исправить уже ничего нельзя.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

libstdc++ не кинет исключение в единице трансляции собранной с - fno-exceptions

annulen ★★★★★
()
Ответ на: комментарий от Lzzz

Так это просто делается, перехватываешь исключение как можно ближе к месту вызова и дергаешь abort(), _exit(1) или что подходит в задаче

annulen ★★★★★
()
Ответ на: комментарий от Lzzz

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

annulen ★★★★★
()
Ответ на: комментарий от annulen

переходить на язык с GC

ну перейдёшь ты, а там - сюрприз - финализаторы!
это примерно такая же хрень как деструкторы
если при удалении объекта нужно сделать что-то ещё кроме тупого освобождения памяти, то финализатор обязателен

Egor_
()
Ответ на: комментарий от Lzzz

А как синхронизовать время жизни объекта и этого глобального контроллера? Нужно копировать все указатели на выделенные ресурсы?

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

Мы говорим о соединениях, если я правильно понял.

1. Во-первых, я так и не понял, что входит в понятие «закрыть соединение», и почему это происходит дольше, чем если это делает система при abort()

2. Во-вторых, если что-то и вправду выполняется долго, то имеет смысл сделать lifecycle, вроде «открывается», «используется», «закрывается», «закрыто». Контроллер мог бы владеть пулом соединений, и управлять выдачей. Соответственно, если какой-то объект требует подключения, то запрашивает контроллер, тот выдает подключение, объект его использует. В деструкторе объект просто отдает подключение контроллеру (вызывает метод «больше не использую»), что быстро, а контроллер в параллель выполняет всю работу по закрытию, не держит деструктор.

Эта модель расширяемая, например, если подключения могут быть открыты до того, как будет использоваться объектами, а процедура открытия длительная, то контроллер может держать определенное количество открытых соединений; тогда выдача будет моментальной; а когда объект отдает соединение, оно может не закрываться, а ждать пока другой объект его запросит. Ну, и контроллировать сколько таких запасных соединений может быть, лишние закрывать. Тогда добавляем lifecycle фазу «не используется».

В книгах написано, что в raii лучшее место для освобождение это деструктор.

Нельзя бездумно использовать фреймворки.
С другой стороны, если фреймворк не подходит, нужно чётко понимать почему. Поэтому меня очень интересует ответ на вопрос 1 выше.

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 2)
Ответ на: комментарий от Lzzz

В erlang именно так и работает, немного изучала

Erlang - это язык. Как на нем напишешь, так и будет работать.

Наверное то были какие-то hello word примеры, или раздел «ну, еще можно так». Но в реальной жизни так делать нельзя. Потому, как если программа вылетела, то это баг, ну или проблема в окружении программы. В любом случае нужно начинать разбирательство. Автохилинг - он для другого.

Короче, никогда так не делай.

Kroz ★★★★★
()
Ответ на: комментарий от RazrFalcon

Их уже можно пробрасывать без лапшы в стиле Go?

Канеш! Берёшь functional template library с монадами и пробрасываешь. Там даже оператор >>= есть, прямо как в хацкелле!

hateyoufeel ★★★★★
()
Ответ на: комментарий от dave

А примитивы примитивными.

Всегда поражался таким объяснениям. Что значит исключительные?

anonymous
()
Ответ на: комментарий от Kroz

На вопрос 1. Например, нужно дождаться запрос от клиента (когда он придет никто не знает) и вернуть ему код ошибки.

Вообще я учусь, это не реальные программы, а скорей упражнения.

Lzzz
() автор топика
Ответ на: комментарий от Kroz

никогда так не делай

Я где-то читала, люди попали в ситуацию, когда текла память в java программе. Они сделалали 2 (или 4) экземпляра программы, которые перегружали по очереди. И все работало.

Lzzz
() автор топика
Ответ на: комментарий от RazrFalcon

Можно свой std::visit написать или адаптер к range.

Внутри будут if, но когда пользуешься этого не будет видно.

Или какие-нибудь библиотеки использовать для этого.

fsb4000 ★★★★★
()
Ответ на: комментарий от Kroz

Она не совсем верно поняла идею. В эрланге охулиард зелёных тредов которые спавнятся на каждый чих - там так и надо. И там действительно для лучшей latency регулярно используется подход - воркера с ошибкой пристреливаем, запускаем нового. Другое дело что там воркер это расходник и соединениями он не управляет, а кто управляет, там и ошибки обрабатывают и проверками обмазывают.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Lzzz

Так php разработчики испокон веков так делают. php не умеет не течь.

А вообще, если это не production код, то можешь забить на обработку исключений, если тебе выгодно как можно быстрее упасть. Дело в том, что вызывать или не вызывать деструкторы(раскручивать стек) перед вызовом terminate(если исключение никто не поймал) - это implementation-defined решение оставленное на усмотрение разработчиков с++ runtime. И gcc/llvm раскрутку стека не делают. Тебе этого должно хватить.

anonymous
()
Ответ на: комментарий от Lzzz

Тебе пока ты учишься, надо научиться делать правильно. Через жопу само получится.

Я наблюдал ситуации когда просто отрубали GC и мусор не собирался совсем. Точнее собирался он раз в сутки при перезапуске инстанса. Всё во имя latency и стабильного времени отклика. Только это не значит что так надо делать, подобные штуки как раз применяют только в очень специфичных областях когда точно знают что делают и какие последствия это за собой несёт.

А то что ты говоришь - это классические «костыли». Да, так тоже можно, но это «путь пи^Wговнокодеров».

Dark_SavanT ★★★★★
()
Ответ на: комментарий от anonymous

Потому что когда ты ходишь за пивом в ларёк, покупаешь и идёшь обратно - это обычная ситуация.

Когда в ларьке пиво закончилось - это ожидаемая ошибка

А когда тебе прилетело арматуриной в процессе покупки - исключительная

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

А когда тебе прилетело арматуриной в процессе покупки - исключительная

Называется - «Тушите свечи».

anonymous
()
Ответ на: комментарий от Lzzz

Спорное решение. Тут насоветуют как хорошего так и не очень.

А так - у тебя скорее всего слишком много всего намотано на деструктор и/или просто неправильно спроектирована работа.

graсeful shutdown это конечно хорошо, но обе стороны и сервер и клиент должны уметь правильно обрабатывать ситуацию когда соединение просто порвалось. Такое бывает причём довольно часто и для современных сетей это норма.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от anonymous

Не обязательно, в скорой эту ситуацию могут обработать и вернуть тебя обратно к ларьку. А могут не обработать и оставить как есть.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Dark_SavanT

Не обязательно, в скорой эту ситуацию могут обработать и вернуть тебя обратно к ларьку. А могут не обработать и оставить как есть.

И как доктора исправят деление на ноль?

anonymous
()
Ответ на: комментарий от anonymous

Не исправят(исключение не обработано) и ты поедешь к всевышнему.

А если там не деление на ноль, а просто шишка на голове - дадут каску и вернут к ларьку(обработали исключение, приняли меры, продолжаем выполнение).

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Lzzz

Я где-то читала, люди попали в ситуацию, когда текла память в java программе. Они сделалали 2 (или 4) экземпляра программы, которые перегружали по очереди. И все работало.

Различай устранение инцидента и решение проблемы.

Когда у тебя на программе основан бизнес, то каждая минута простоя стоит денег.

Допустим, ты обнаружила, что у тебя происходят сбои из-за того, что течет память. Теперь у тебя 2 задачи:
1. Решение проблемы: найти из-за чего течет память и устранить этот баг - сделать так, чтобы память не текла.
2. Поскольку на устранение бага может занять длительное время - часы, дни недели (кодинг, тестирование, деплоймент на реалное окружение), то на это время нужно сделать так, чтобы просто работало - пусть через костыли, пусть неоптимально, но чтобы работало и приносило денег. Поэтому делают временное обходное решение чтобы решить инцидент; то, что ты описала, очень на это похоже. Но это временно! Это ни в коем случае не может считаться нормальным решением проблемы. Как только решат проблему - устранят утечку памяти - временные/обходные решения убирают (как правило).

Детальней здесь:
https://www.itexpert.ru/rus/ITEMS/proces/#pui
https://www.itexpert.ru/rus/ITEMS/proces/#pup

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 2)
Ответ на: комментарий от Dark_SavanT

… дадут каску и вернут к ларьку

У меня раньше было просто.
Пользователь всегда получал результат.
Если что-то было не правильно, то звонили.
Все ошибки помещал в лог и быстренько их исправлял.

anonymous
()
Ответ на: комментарий от Egor_

Вот только выполняться он будет отложенно, чтобы не создавать затык при массовых удалениях, а в топовых реализациях вообще в отдельном потоке

annulen ★★★★★
()
Ответ на: комментарий от zendrz

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

Ошибочные разрывы (например, HTTP 404) запросто могут приводить к исключениям.

Kroz ★★★★★
()
Ответ на: комментарий от kardapoltsev

В жабе есть jit который может определить, что какое-то исключение выбрасывается часто, и соптимизировать его, а в с++ это всегда чп

annulen ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.