Каким образом исключения C ++ замедляют работу кода, когда исключений нет?

StackOverflow https://stackoverflow.com/questions/1897940

  •  19-09-2019
  •  | 
  •  

Вопрос

Я читал, что использование исключений C ++ для обработки исключений сопряжено с некоторыми накладными расходами, в отличие, скажем, от проверки возвращаемых значений.Я говорю только о накладных расходах, которые возникают, когда не генерируется исключение.Я также предполагаю, что вам нужно было бы реализовать код, который фактически проверяет возвращаемое значение и выполняет соответствующие действия, независимо от того, что было бы эквивалентно тому, что сделал бы блок catch.И также несправедливо сравнивать код, который генерирует объекты исключения с 45 переменными состояния внутри, с кодом, который возвращает отрицательное целое число для каждой ошибки.

Я не пытаюсь аргументировать за или против исключений C ++ исключительно на основе того, какие из них могут выполняться быстрее.Недавно я слышал, как кто-то доказывал, что код, использующий исключения, должен выполняться так же быстро, как код, основанный на кодах возврата, если учесть весь дополнительный бухгалтерский код, который потребуется для проверки возвращаемых значений и обработки ошибок.Что я упускаю из виду?

Это было полезно?

Решение

Существуют затраты, связанные с обработкой исключений на некоторые платформ и с некоторые компиляторы.

А именно, Visual Studio при создании 32-разрядного целевого объекта зарегистрирует обработчик в каждой функции, имеющей локальные переменные с нетривиальным деструктором.По сути, это создает try/finally обработчик.

Другая техника, используемая gcc и Visual Studio, ориентированная на 64-разрядные версии, накладные расходы возникают только тогда, когда исключение брошенный (этот метод включает в себя обход стека вызовов и поиск по таблице).В случаях, когда исключения генерируются редко, это может фактически привести к созданию более эффективного кода, поскольку коды ошибок не нужно обрабатывать.

Другие советы

Только попробуйте / catch и попробуйте /except заблокировать, выполнив несколько инструкций по настройке.Накладные расходы, как правило, должны быть незначительными во всех случаях, за исключением самых затянутых циклов.Но обычно вы все равно не стали бы использовать try /catch/except во внутреннем цикле.

Я бы посоветовал не беспокоиться об этом и вместо этого использовать профилировщик для оптимизации вашего кода там, где это необходимо.

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

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

Там является некоторые накладные расходы с исключениями (как указывалось в других ответах).

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

Работают ли они с отключенными исключениями?

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

Только накладные расходы составляют ~ 6 инструкций, которые добавляют 2 SEH в начале функции и оставляют их в конце.Независимо от того, сколько попыток / уловов у вас есть в потоке, это всегда одно и то же.

Кроме того, что это такое с локальными переменными?Я слышу, как люди всегда жалуются на них при использовании try / catch.Я этого не понимаю, потому что деконструкторы в конечном итоге все равно были бы вызваны.Кроме того, вы не должны допускать, чтобы исключение увеличивалось более чем на 1-3 вызова.

Я взял тестовый код Chip Uni и немного расширил его.Я разделил код на два исходных файла (один с исключениями;один без).Я запустил каждый бенчмарк 1000 раз, и я использовал clock_gettime() с CLOCK_REALTIME для записи времени начала и окончания каждой итерации.Затем я вычислил среднее значение и дисперсию полученных данных.Я провел этот тест с 64-разрядными версиями g ++ 5.2.0 и clang ++ 3.7.0 на процессоре Intel Core i7 с 16 ГБ оперативной памяти, который запускает ArchLinux с ядром 4.2.5-1-ARCH.Вы можете найти расширенный код и полные результаты здесь.

g++

Никаких исключений
  • Средний:30,022,994 наносекунды
  • Стандартное Отклонение:1.25327e+06 наносекунд
Исключения
  • Средний:30,025,642 наносекунды
  • Стандартное Отклонение:1.83422e+06 наносекунд

лязг++

Никаких исключений
  • Средний:20,954,657 наносекунд
  • Стандартное Отклонение:426,662 наносекунды
Исключения
  • Средний:23,916,638 наносекунд
  • Стандартное Отклонение:1.72583e+06 наносекунд

Исключения C ++ влекут за собой нетривиальное снижение производительности только с clang ++, и даже это снижение составляет всего ~ 14%.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top