На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Исключения и производительность , практика
    Очень много писалось и говорилось об исключениях и производительности, но время бежит, а мощности ростут, компиляторы и язык совершенствуются.
    Как уменьшить потери при использовании исключений? Возможно ли? Интересует в первую очередь практическая сторона. Возможно кто-то уже решал подобные задачи, проводил тесты и т.д. Может кому-то пришлось отказаться от исключений вовсе?
    Хотелось бы обсудить (именно обсудить, а не разводить очередной холивар) все возможные решения проблемы.
      Сейчас сам пишу 3D графический движок, отказался от исключений вообще, производительность снижается заметно, гораздо лучше использовать возвращаемые значения о состоянии выпонения функции. Сам довольно мало испытывал исключения, так как я любитель наиболее оптимального кода и стараюсь использовать вставки на асемблере по максимуму (если это не очень сильно снижает скорость разработки программы).
        x0ras
        Исключения, конечно, снижают производительность. Но не нужно забывать о том, что исключения, в идеале, должны возникать не слишком часто. А если исключения не использовать, то придется каждый вызов функции обрамлять операторами проверки возвращаемого значения, причем эти операторы будут работать всегда, а исключение только во время возникновения ошибки. Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения. Ну, а про читабельность кода я уже не говорю...
          Цитата artalex @
          Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения.

          не могут. сколько раз писалось, даже если они не возникают, они тормозят прогу.
            Цитата Sazabis @
            Цитата (artalex @ Сегодня, 17:23)
            Так что иногда исключения могут оказаться быстрее, чем проверки возвращаемого значения.
            не могут. сколько раз писалось, даже если они не возникают, они тормозят прогу.

            Чем? При каком компиляторе?
              Давайте по порядку.

              1) если исключения не возникают, то прога практически не тормозится
              2) исключения В ЛЮБОМ СЛУЧАЕ будут медленне нежели обычная проверка возвращаемого значения. х0ras-а интересует, как повысить производительность. Ответ - практически никак. Писать свои исключения, менеджеры памяти и т.д. Это связано прежде всего с кодом, который генерируется для "отката". В теневой стек должны быть записаны адреса объектов, которые должны быть разрушены при ненормальной раскрутке. Это процесс довольно быстрый, но он в любом случае занимает ненулевое время.
              3) раскрутка стека. Само исключение так же живёт не в стеке (хотя бывает, и живёт, в отдельных реализациях), чаще всего они лежат либо в теневом стеке, либо в куче. А с ними операции тоже не самые быстрые.
              4) исключения - это шаг, на который можно и нужно идти, по крайней мере, на этапе отладки. Нп, написать что нибудь типа функций/макросов check_value(), которые в релиз версии должны быть заменены на пустые значения.
              5) проверка возвращаемых значений - это прекрасно, т.к. быстрее неё ничего не будет. Но... они хороши в индивидуальной разработке. Когда ты реально можешь грамотно и польностью протестировать весь написаный код. В коммандной разработке часто используются подобные check_value.
                Если говорить о программировании под Windows, то там обработка исключений настолько встроена в систему ( SEH ), что 1) гарантируется минимум накладных расходов, 2)даже если вы сами не используете исключения, определённые структуры для их обработки всё равно поддерживаются. Всё равно в TEB каждого thread-а есть EXCEPTION_REGISTRATION - список обработчиков исключений. Когда вы пишите __try/__except или try/catch, то компилятор создаёт на стеке структуру EXCEPTION_REGISTRATION и добавляет ваш обработчик в список. Таким образом, при использовании исключений у вас чуть увеличивается объём использованного стека и добавляется пара ассемблерных команд в духе
                ExpandedWrap disabled
                  _asm move fs[off_EXCEPTION_REGISTRATION], handler_addr

                Моё утверждение следующее: пока не происходит исключение, почти нет потери производительности. Практический пример - видела тысячу и одну рекоммендацию драйверистам касательно использования SEH-а, а вряд ли кто станет возражать, что в драйвере, да ещё в обработчиках ISR-ов, время является весьма критичным ресурсом.
                Возможно, я некорректно понимаю, и в данной теме под использованием механизма исключений подразумевалась не обработка экстренных ситуаций и не разовые переходы ( как-то при завершении программы ), а именно регулярное использование исключений для передачи управления на другой уровень программы?
                  Цитата Lucifer @
                  Чем? При каком компиляторе?

                  компилятор не важен, а чем, тут уже лучше меня написли.
                  сдаеться мне, автор и сам понимает это.
                  Цитата x0ras @
                  Как уменьшить потери при использовании исключений?


                  Вопрос в скорости, позволят ли современные машины обрабатывать код с исключениями быстро ? Тут уже дело перформенс тестов: допустимо такое время или нет. А потери всегда будут равноценными, при наличии одного кол-ва обработчиков, для ветви кода <- имхо. Или есть другие мнения ?
                    Цитата TrefptYc @
                    Если говорить о программировании под Windows, то там обработка исключений настолько встроена в систему ( SEH ), что 1) гарантируется минимум накладных расходов, 2)даже если вы сами не используете исключения, определённые структуры для их обработки всё равно поддерживаются.

                    Проблема в другом - это не C++-ные исключения. А потому при их выстреливании никаких побочных эффектов, гарантированных для исключений С++ (как то раскрутка стека, вызов деструкторов и т. п.) не происходит.
                      Цитата Flex Ferrum @
                      Проблема в другом - это не C++-ные исключения. А потому при их выстреливании никаких побочных эффектов, гарантированных для исключений С++ (как то раскрутка стека, вызов деструкторов и т. п.) не происходит.

                      Позвольте, позвольте!
                      Выдержка из одной из статей Мэтта Питрика (Matt Pietrek) касательно SEH.
                      Цитата
                      I'm going to avoid the issue of true C++ exception handling, which uses catch() instead of _except. Under the hood, true C++ exception handling is implemented very similarly to what I'll describe here


                      И как это нет раскрутки стека или деструкторов? А если обработчик вызывается с флагом EH_UNWINDING
                      Цитата
                      What does EH_UNWINDING mean? When an exception callback is invoked with the EH_UNWINDING flag, the operating system is giving the handler function an opportunity to do any cleanup it needs to do. What sort of cleanup? A perfect example is that of a C++ class destructor. When a function's exception handler declines to handle an exception, control typically doesn't exit from that function in a normal manner. Now, consider a function with a C++ class declared as a local variable. The C++ specification says that the destructor must be called. The exception handler callback with the EH_UNWINDING flag is the opportunity for the function to do cleanup work such as invoking destructors and _finally blocks.
                        Цитата TrefptYc @
                        И как это нет раскрутки стека или деструкторов? А если обработчик вызывается с флагом EH_UNWINDING

                        Ну, значит я отстал от жизни.
                          В SEH в Win32 ЕСТЬ раскрутка стека... Компилятор MSVC++ даже стандартные исключения С++ (throw, catch) преобразует в вызовы _try, _except. З.Ы. я точно не помню, как именно, надо перечитать Джеффри Рихтера :P
                            Что значит, обработка исключений встроена в систему? И как это может отражаться на производительности?

                            Если
                            а) исключительная ситуации в программе перехватывается операционной системой, то даже не знаю как из этой ситуации выбираться, так как выглядит она совершенно неуправляемой;
                            б) при возникновении исключительной ситуации программа выполняет системный вызов для размотки стека, тогда вижу две основные проблемы: первая, системный вызов - это неизбежная потеря времени, при том что ОС не может выполнить связанную с ситуацией работу быстрее, чем сама программа; вторая, в ОС вынужденно встраиваются обработчики исключительных ситуаций всех языков, допускающих обработку исключений, что увеличивает её размер и делает её ещё неповоротливей.
                            в) система обнаруживает исключительные ситуации во время системных вызовов и предупреждает о них вызывающую программу, что позволяет последней адекватно реагировать на ошибки, ну это делали все операционные системы, чуть ли не с момента появления самого понятия "операционная система". Или к разработчикам Windows эта очевидная мысль пришла только сейчас?
                            В DOS такой механизм действовал.
                            г) система позволяет выбрасывать исключения из Callback-функций, корректно обрабатывая их. Идея выглядит здраво, но по некотором размышлении её придётся ограничить, чтобы выбрасывать можно было определённое множество исключений.

                            Таким образом определённо бракуются а и б, нормально поддерживается в и частично г.
                            Лично я стараюсь избегать исключений, анализируя ситуацию заранее. Если например я знаю, что функция не обрабатывает отрицательных параметров, то для обработки их создаю альтернативную ветку, а не перехватываю исключение, даже если оно из неё выбрасывается.
                              Цитата
                              Что значит, обработка исключений встроена в систему? И как это может отражаться на производительности?

                              Обработка исключений встроена в систему значит то, что система берет на себя обязанность (или часть обязанности) по раскрутке стека. Также система рпедоставляет функции для программного выкидывания исключений.

                              Цитата
                              а) исключительная ситуации в программе перехватывается операционной системой, то даже не знаю как из этой ситуации выбираться, так как выглядит она совершенно неуправляемой;

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

                              Цитата
                              Когда вы пишите __try/__except или try/catch, то компилятор создаёт на стеке структуру EXCEPTION_REGISTRATION и добавляет ваш обработчик в список. Таким образом, при использовании исключений у вас чуть увеличивается объём использованного стека и добавляется пара ассемблерных команд в духе

                              :yes:
                              А если учесть, что во всей программе всего несколько блоков try/catch, то издержки несущественны. Более того, обычно программа без использования исключений строится следующим способом:
                              ExpandedWrap disabled
                                int f1_1() {
                                ...
                                }
                                 
                                int f1_2() {
                                ...
                                }
                                 
                                int f1_3() {
                                ...
                                }
                                 
                                int f2_1() {
                                if(!f1_1())
                                    // return error;
                                if(!f1_2())
                                    // return error;
                                if(!f1_3())
                                    // return error;
                                 
                                    ...
                                }
                                 
                                int f2_2() {
                                if(!f1_1())
                                    // return error;
                                if(!f1_2())
                                    // return error;
                                if(!f1_3())
                                    // return error;
                                 
                                    ...
                                }
                                 
                                int f() {
                                if(!f2_1()) {
                                   // return error;
                                if(!f2_2())
                                   // return error;
                                 
                                   ...
                                }

                              Суть в том, что у нас много вложенных вызовов (обычно "высокоуровневые" функции обращаются к функциям "более низкого уровня"), и в каждом случае значение проверяется с помощью if. Количество этих проверок несравнимо больше, чем количество блоков try/catch. При этом операция условного перехода заметно влияет на производительность (по сравнению с mov, например). При использовании исключений проверка ошибок с помощью if присутсвтует только на самом "нижнем" уровне. Остальным функциям в большинстве случаев это не требуется.

                              Далее, если всё-таки вываливается исключение. Тут говорить нечего, конечно это накладно по сравнению с проверкой условия. НО! После выброса исключения обычно задумываться о производительности не приходится. Исключения составляют, пожалуй, лишь программы, обслуживающие много пользователей, в ходе выполнения которых возникает нехватка системных ресурсов (памяти, например), и надо обеспечить остальным пользователям (которым хватило ресурсов) быстрое выполнение. Однако в таких случаях разумнее установить настраиваемое ограничение на количество пользователей/ресрусов, т. к. например Windows при нехватке памяти может просто убить процесс без всяких исключений.

                              Кроме того, используя аппаратные исключения SEH (ошибки доступа к памяти), можно нашаманить более быстрое приложение, которое работает с большими объемами данных (пример у Рихтера).
                                Вообще-то аппаратные исключения по стандарту языка C++ как бы и не совсем исключения. По крайней мере их перехват затруднён. Думаю часто хватило бы просто возможности оповестить программу о возникновении такой ситуации.
                                Раскрутка стека программы операционной системой затруднена хотя бы потому, что программа может использовать какую-то свой, не определённый в системе метод хранения необходимой информации. А так и получится, если программа строится компилятором/сборщиком сторонних фирм, а не создателя ОС. В случае с Windows это особенно актуально, так как MS известна своим пристрастием включать в свои ОС недокументированные возможности.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0406 ]   [ 15 queries used ]   [ Generated: 17.07.25, 23:12 GMT ]