Во время проверки кода с сотрудником Microsoft мы наткнулись на большой раздел кода внутри try{}
блока. Она и ИТ-представитель предположили, что это может повлиять на производительность кода. Фактически, они предложили, чтобы большая часть кода была за пределами блоков try / catch, и что должны проверяться только важные разделы. Сотрудник Microsoft добавил и сказал, что предстоящий технический документ предостерегает от неправильных блоков try / catch.
Я осмотрелся и обнаружил, что это может повлиять на оптимизацию , но, похоже, это применимо только тогда, когда переменная является общей для областей.
Я не спрашиваю о поддерживаемости кода или даже об обработке правильных исключений (рассматриваемый код, без сомнения, нуждается в перефакторинге). Я также не имею в виду использование исключений для управления потоком, в большинстве случаев это явно неправильно. Это важные вопросы (некоторые из них более важны), но не здесь.
Как блоки try / catch влияют на производительность, когда исключения не генерируются?
источник
Ответы:
Проверь это.
Вывод:
В миллисекундах:
Новый код:
Новые результаты:
источник
После просмотра всей статистики для try / catch и без try / catch любопытство заставило меня оглянуться назад, чтобы увидеть, что генерируется для обоих случаев. Вот код:
C #:
MSIL:
C #:
MSIL:
Я не эксперт по IL, но мы можем видеть, что локальный объект исключения создается в четвертой строке
.locals init ([0] class [mscorlib]System.Exception ex)
после этого, все примерно так же, как для метода без try / catch до строки семнадцатьIL_0021: leave.s IL_002f
. Если возникает исключение, элемент управления переходит к строке, вIL_0025: ldloc.0
противном случае мы переходим к меткеIL_002d: leave.s IL_002f
и функция возвращается.Я могу с уверенностью предположить, что если исключений не возникает, то это накладные расходы на создание локальных переменных для хранения
толькообъектов исключений и инструкции перехода.источник
Нет. Если тривиальные оптимизации, которые исключает блок try / finally, действительно оказывают ощутимое влияние на вашу программу, вам, вероятно, не следует использовать .NET в первую очередь.
источник
Довольно полное объяснение модели исключений .NET.
Особенности Рико Мариани: исключительная стоимость: когда бросать, а когда нет
Дмитрий Заславский:
источник
Структура отличается в примере от Ben M . Это будет расширено внутри
for
цикла, что приведет к плохому сравнению между этими двумя случаями.Следующее является более точным для сравнения, когда весь код для проверки (включая объявление переменной) находится внутри блока Try / Catch:
Когда я запустил оригинальный тестовый код от Ben M , я заметил разницу в конфигурации Debug и Releas.
В этой версии я заметил разницу в отладочной версии (на самом деле больше, чем в другой версии), но не было никакой разницы в версии выпуска.
Conclution :
На основании этих испытаний, я думаюмы можем сказатьчто Try / Поймать делает оказывает незначительное влияние на производительность.
РЕДАКТИРОВАТЬ:
я попытался увеличить значение цикла с 10000000 до 1000000000, и снова запустил в выпуске, чтобы получить некоторые различия в выпуске, и результат был следующим:
Вы видите, что результат не имеет значения. В некоторых случаях версия, использующая Try / Catch, на самом деле быстрее!
источник
try/catch
здесь. Вы рассчитываете 12 попыток входа в критическую секцию против 10М циклов. Шум петли уничтожит любое влияние try / catch. если вместо этого вы помещаете try / catch в узкий цикл и сравниваете с / без, вы в конечном итоге получите стоимость try / catch. (Без сомнения, такое кодирование обычно не является хорошей практикой, но если вы хотите рассчитать время, затрачиваемое на конструкцию, вы так и сделаете). В настоящее время BenchmarkDotNet - это инструмент для обеспечения надежного времени выполнения.Я проверил фактическое воздействие
try..catch
в узком цикле, и оно само по себе слишком мало, чтобы быть проблемой производительности в любой нормальной ситуации.Если цикл делает очень мало работы (в моем тесте я сделал
x++
), вы можете измерить влияние обработки исключений. Цикл с обработкой исключений выполнялся примерно в десять раз дольше.Если цикл выполняет некоторую фактическую работу (в моем тесте я назвал метод Int32.Parse), обработка исключений имеет слишком мало влияния, чтобы его можно было измерить. Я получил гораздо большую разницу, меняя порядок циклов ...
источник
блоки try catch имеют незначительное влияние на производительность, но исключение Бросок может быть довольно значительным, возможно, именно здесь ваш коллега запутался.
источник
Попробовать / поймать оказывает влияние на производительность.
Но это не огромное влияние. сложность try / catch обычно равна O (1), как и простое присваивание, за исключением случаев, когда они помещаются в цикл. Поэтому вы должны использовать их с умом.
Вот справочник по производительности try / catch (хотя и не объясняет его сложность, но подразумевается). Взгляните на раздел « Бросьте меньше исключений »
источник
Теоретически, блок try / catch не будет влиять на поведение кода, если только не произойдет исключение. Однако есть некоторые редкие обстоятельства, когда наличие блока try / catch может иметь существенный эффект, и некоторые необычные, но едва ли неясно, где эффект может быть заметен. Причина этого в том, что данный код выглядит так:
Компилятор может быть в состоянии оптимизировать оператор Statement1, основываясь на том факте, что оператор2 гарантированно будет выполняться перед оператором3. Если компилятор может распознать, что thing1 не имеет побочных эффектов, а thing2 фактически не использует x, он может полностью пропустить thing1. Если бы [как в этом случае] вещь 1 была дорогой, это могло бы стать основной оптимизацией, хотя случаи, когда вещь 1 дорогая, также являются теми, которые компилятор с наименьшей вероятностью оптимизировал бы. Предположим, что код был изменен:
Теперь существует последовательность событий, где оператор 3 может выполняться без выполнения оператора 2. Даже если ничто в коде для
thing2
не может вызвать исключение, возможно, что другой поток может использовать очищенноеInterlocked.CompareExchange
замечаниеq
и установить его в значениеThread.ResetAbort
, а затем выполнить операторThread.Abort()
before до записи его значенияx
. Затемcatch
выполняетсяThread.ResetAbort()
[через делегатаq
], что позволяет продолжить выполнение с оператором 3. Такая последовательность событий, конечно, была бы исключительно невероятной, но компилятор должен генерировать код, который работает в соответствии со спецификацией, даже когда происходят такие невероятные события.В целом, компилятор гораздо чаще замечает возможности пропустить простые фрагменты кода, чем сложные, и, таким образом, было бы редко, чтобы попытка-отловка могла сильно повлиять на производительность, если исключения никогда не генерируются. Тем не менее, есть некоторые ситуации, когда наличие блока try / catch может помешать оптимизации, которая - но для try / catch - позволила бы коду выполняться быстрее.
источник
Хотя « профилактика лучше, чем обработка », с точки зрения производительности и эффективности мы могли бы выбрать опробование вместо предварительной вариации. Рассмотрим следующий код:
Вот результат:
источник
См. Обсуждение реализации try / catch для обсуждения того, как работают блоки try / catch, и как некоторые реализации имеют высокие издержки, а некоторые - нулевые, когда не возникает исключений. В частности, я думаю, что 32-битная реализация Windows имеет большие издержки, а 64-битная реализация - нет.
источник