Итак, я знаю, что команда try / catch добавляет некоторые накладные расходы и, следовательно, не является хорошим способом управления потоком процесса, но откуда эти накладные расходы и каково их реальное влияние?
источник
Итак, я знаю, что команда try / catch добавляет некоторые накладные расходы и, следовательно, не является хорошим способом управления потоком процесса, но откуда эти накладные расходы и каково их реальное влияние?
Я не эксперт в языковых реализациях (так что относитесь к этому с недоверием), но я думаю, что одна из самых больших затрат - это раскручивание стека и сохранение его для трассировки стека. Я подозреваю, что это происходит только тогда, когда генерируется исключение (но я не знаю), и если это так, это будет приличная скрытая стоимость каждый раз, когда генерируется исключение ... так что это не похоже на то, что вы просто прыгаете с одного места в коде к другому много чего происходит.
Я не думаю, что это проблема, если вы используете исключения для ИСКЛЮЧИТЕЛЬНОГО поведения (то есть не для вашего типичного ожидаемого пути в программе).
Здесь следует отметить три момента:
Во-первых, наличие блоков try-catch в вашем коде практически не влияет на производительность. Это не должно быть соображением, когда вы пытаетесь избежать их использования в вашем приложении. Ухудшение производительности вступает в игру только при возникновении исключения.
Когда возникает исключение в дополнение к операциям разматывания стека и т. Д., Которые имеют место, о которых упоминали другие, вы должны знать, что происходит целая куча вещей, связанных со средой выполнения / отражением, чтобы заполнить члены класса исключения, такие как трассировка стека объект и различные члены типов и т. д.
Я считаю, что это одна из причин, почему общий совет, если вы собираетесь повторно генерировать исключение, состоит в том, чтобы просто
throw;
не генерировать исключение снова или создавать новое, поскольку в этих случаях вся эта информация стека собирается повторно, тогда как в простом выкинуть это все сохранилось.источник
throw new Exception("Wrapping layer’s error", ex);
Вы спрашиваете о накладных расходах при использовании try / catch / finally, когда исключения не генерируются, или о накладных расходах, связанных с использованием исключений для управления потоком процесса? Последнее в некоторой степени похоже на использование динамитной шашки для зажигания свечи на день рождения малыша, и связанные с этим накладные расходы относятся к следующим областям:
Вы можете ожидать дополнительных ошибок страницы из-за сгенерированного исключения, обращающегося к нерезидентному коду и данным, которые обычно не входят в рабочий набор вашего приложения.
оба вышеперечисленных элемента обычно обращаются к «холодному» коду и данным, поэтому серьезные сбои страницы вероятны, если у вас вообще нехватка памяти:
Что касается фактического влияния стоимости, она может сильно различаться в зависимости от того, что еще происходит в вашем коде в то время. У Джона Скита есть хорошее резюме с некоторыми полезными ссылками. Я склонен согласиться с его утверждением, что если вы дойдете до того момента, когда исключения значительно ухудшат вашу производительность, у вас возникнут проблемы с точки зрения использования исключений, выходящие за рамки производительности.
источник
По моему опыту, самые большие накладные расходы связаны с созданием исключения и его обработкой. Однажды я работал над проектом, в котором код, подобный приведенному ниже, использовался для проверки, имеет ли кто-то право редактировать какой-либо объект. Этот метод HasRight () использовался повсюду на уровне представления и часто вызывался для сотен объектов.
Когда тестовая база данных наполнялась тестовыми данными, это приводило к очень заметному замедлению при открытии новых форм и т. Д.
Поэтому я изменил его на следующее, что, согласно более поздним быстрым и грязным измерениям, примерно на 2 порядка быстрее:
Короче говоря, использование исключений в нормальном потоке процесса примерно на два порядка медленнее, чем использование аналогичного потока процесса без исключений.
источник
Вопреки общепринятым теориям,
try
/catch
может иметь значительные последствия для производительности, независимо от того, выбрасывается ли исключение или нет!Первый из них был освещен в нескольких сообщениях в блогах Microsoft MVP на протяжении многих лет, и я верю, что вы можете легко их найти, но StackOverflow так заботится о контенте, поэтому я предоставлю ссылки на некоторые из них в
качестве дополнительныхдоказательств:try
/catch
/ на производительностьfinally
( и вторая часть ) Питера Ричи исследует оптимизацию, которуюtry
/catch
/finally
отключает (и я расскажу об этом подробнее, используя цитаты из стандарта)Parse
сравнению сTryParse
противConvertTo
Яна Huff говорится откровенночто «обработка исключений очень медленно» и демонстрирует эту точку изъязвленияInt.Parse
иInt.TryParse
друг против друга ... Для техкто настаиваетчтоTryParse
использованиеtry
/catch
за кулисами, это должно пролить некоторый свет!Также есть ответ, который показывает разницу между дизассемблированным кодом с использованием
try
/ и без негоcatch
.Это кажется настолько очевидным , что это накладные расходы , которое явно наблюдается в генерации кода, и накладные расходы , даже , кажется, признают людей , которые ценят Microsoft! Тем не менее, я повторяю интернет ...
Да, есть десятки дополнительных инструкций MSIL для одной тривиальной строчки кода, и это даже не касается отключенных оптимизаций, так что технически это микро-оптимизация.
Я опубликовал ответ несколько лет назад, который был удален, поскольку он был ориентирован на производительность программистов (макрооптимизация).
Это прискорбно, поскольку никакая экономия процессорного времени на несколько наносекунд, скорее всего, не компенсирует многие часы ручной оптимизации людьми. За что ваш босс платит больше: час вашего времени или час работы за компьютером? В какой момент мы откажемся от сети и признаем, что пора просто купить более быстрый компьютер ?
Ясно, что мы должны оптимизировать наши приоритеты , а не только наш код! В своем последнем ответе я обратил внимание на различия между двумя фрагментами кода.
Использование
try
/catch
:Не используется
try
/catch
:Рассмотрим с точки зрения разработчика обслуживания, который с большей вероятностью потратит ваше время, если не профилирование / оптимизация (описанные выше), которые, вероятно, даже не понадобились бы, если бы не проблема
try
/catch
, а затем при прокрутке исходный код ... Одна из них содержит четыре лишних строчки шаблонного мусора!По мере того как в класс вводится все больше и больше полей, весь этот шаблонный мусор накапливается (как в исходном, так и в дизассемблированном коде), превышая разумные уровни. Четыре дополнительных строки на поле, и это всегда одни и те же строки ... Разве нас не учили избегать повторений? Я полагаю, мы могли бы спрятать
try
/catch
за какой-нибудь самодельной абстракцией, но ... тогда мы могли бы просто избежать исключений (т.е. использованияInt.TryParse
).Это даже не сложный пример; Я видел попытки создания экземпляров новых классов в
try
/catch
. Учтите, что весь код внутри конструктора может быть исключен из определенных оптимизаций, которые в противном случае автоматически применялись бы компилятором. Какой лучший способ развить теорию о том, что компилятор медленный , в отличие от того, что компилятор делает именно то, что ему велят делать ?Предполагая, что указанным конструктором создается исключение, и в результате возникает некоторая ошибка, плохой разработчик обслуживания должен отследить ее. Это может быть не такая уж простая задача, поскольку в отличие от кода спагетти из кошмара goto ,
try
/catch
может вызывать беспорядки в трех измерениях , поскольку он может перемещаться вверх по стеку не только в другие части того же метода, но и в другие классы и методы. , все из которых будут наблюдаться разработчиком технического обслуживания, трудный путь ! Однако нам говорят, что «goto опасно», хех!В конце я упоминаю, что
try
/catch
имеет свое преимущество, которое заключается в том, что он предназначен для отключения оптимизации ! Это, если хотите, средство отладки ! Это то, для чего он был разработан, и его следует использовать как ...Что оптимизации делать
try
,catch
иfinally
отключить?AKA
Как
try
,catch
иfinally
полезен в качестве средства отладки?они препятствуют записи. Это происходит из стандарта:
12.3.3.13 Операторы try-catch
Другими словами, в начале каждого
try
утверждения:try
оператора, должны быть завершены, что требует блокировки потока для начала, что делает его полезным для отладки условий гонки!try
операторомАналогичная история имеет место для каждого
catch
утверждения; предположим, что внутри вашегоtry
оператора (или вызываемого им конструктора или функции и т. д.) вы назначаете эту бессмысленную переменную (скажем,garbage=42;
), компилятор не может удалить этот оператор, независимо от того, насколько он не имеет отношения к наблюдаемому поведению программы . Задание должно быть выполнено до того , какcatch
блок будет введен.Как бы то ни было,
finally
рассказывает аналогичную унизительную историю:12.3.3.14 Заявления о завершении попытки
12.3.3.15 Операторы try-catch-finally
источник
Не говоря уже о том, что если он находится внутри часто вызываемого метода, это может повлиять на общее поведение приложения.
Например, я считаю использование Int32.Parse плохой практикой в большинстве случаев, поскольку он генерирует исключения для чего-то, что в противном случае можно было бы легко поймать.
Итак, чтобы завершить все, что здесь написано:
1) Используйте блоки try..catch для обнаружения неожиданных ошибок - почти без потери производительности.
2) Не используйте исключения для исключенных ошибок, если вы можете этого избежать.
источник
Я написал об этом статью некоторое время назад, потому что в то время многие спрашивали об этом. Вы можете найти его и тестовый код на http://www.blackwasp.co.uk/SpeedTestTryCatch.aspx .
В результате накладные расходы на блок try / catch незначительны, но настолько малы, что их следует игнорировать. Однако, если вы запускаете блоки try / catch в циклах, которые выполняются миллионы раз, вы можете рассмотреть возможность перемещения блока за пределы цикла, если это возможно.
Ключевая проблема с производительностью блоков try / catch - это когда вы действительно перехватываете исключение. Это может добавить заметную задержку в ваше приложение. Конечно, когда что-то идет не так, большинство разработчиков (и многие пользователи) воспринимают паузу как исключение, которое вот-вот произойдет! Ключевым моментом здесь является не использовать обработку исключений для обычных операций. Как следует из названия, они исключительны, и вы должны делать все возможное, чтобы их не выбросили. Вы не должны использовать их как часть ожидаемого потока программы, которая работает правильно.
источник
В прошлом году я сделал запись в блоге на эту тему. Проверить это. Суть в том, что блок try почти не требует затрат, если не возникает исключений - а на моем ноутбуке исключение составляло около 36 мкс. Это может быть меньше, чем вы ожидали, но имейте в виду, что эти результаты находятся в неглубоком стеке. Кроме того, первые исключения очень медленные.
источник
try
/catch
слишком много? Хе-хе), но вы, похоже, спорите со спецификацией языка и некоторыми MVP MS, которые также писали блоги по этой теме, предоставляя измерения вопреки вашему совету ... Я открыт для предположения, что проведенное мной исследование неверно, но мне нужно прочитать вашу запись в блоге, чтобы увидеть, что в нем говорится.try-catch
блок противtryparse()
методов, но концепция та же.Намного проще писать, отлаживать и поддерживать код, свободный от сообщений об ошибках компилятора, предупреждений анализа кода и стандартных принятых исключений (особенно исключений, которые создаются в одном месте и принимаются в другом). Поскольку это проще, код в среднем будет написан лучше и менее ошибочным.
Для меня этот программист и накладные расходы на качество являются основным аргументом против использования try-catch для потока процесса.
Накладные расходы компьютера на исключения незначительны по сравнению с ними и обычно незначительны с точки зрения способности приложения удовлетворять реальным требованиям к производительности.
источник
Мне очень нравится сообщение в блоге Хафтора , и, чтобы добавить свои два цента к этому обсуждению, я хотел бы сказать, что для меня всегда было легко заставить СЛОЙ ДАННЫХ генерировать только один тип исключения (DataAccessException). Таким образом, мой БИЗНЕС-СЛОЙ знает, какого исключения ожидать, и улавливает его. Затем, в зависимости от других бизнес-правил (например, если мой бизнес-объект участвует в рабочем процессе и т. Д.), Я могу создать новое исключение (BusinessObjectException) или продолжить работу без повторной / выброса.
Я бы сказал, не стесняйтесь использовать try..catch всякий раз, когда это необходимо, и используйте его с умом!
Например, этот метод участвует в рабочем процессе ...
Комментарии?
источник
Мы можем прочитать в «Прагматике языков программирования» Майкла Л. Скотта, что современные компиляторы не добавляют никаких накладных расходов в общем случае, то есть, когда не происходит никаких исключений. Таким образом, каждая работа выполняется во время компиляции. Но когда во время выполнения создается исключение, компилятору необходимо выполнить двоичный поиск, чтобы найти правильное исключение, и это будет происходить для каждого нового выброса, который вы сделали.
Но исключения есть исключения, и эта стоимость вполне приемлема. Если вы попытаетесь выполнить обработку исключений без исключений и вместо этого использовать коды ошибок возврата, возможно, вам понадобится оператор if для каждой подпрограммы, и это повлечет за собой действительно накладные расходы в реальном времени. Вы знаете, что оператор if преобразуется в несколько инструкций по сборке, которые будут выполняться каждый раз, когда вы входите в свои подпрограммы.
Извините за мой английский, надеюсь, что он вам поможет. Эта информация основана на цитируемой книге; дополнительную информацию см. В главе 8.5 Обработка исключений.
источник
Давайте проанализируем одну из самых больших возможных затрат на блок try / catch, когда он используется там, где его не нужно использовать:
А вот и без try / catch:
Не считая незначительного пробела, можно заметить, что эти два эквивалентных фрагмента кода имеют почти одинаковую длину в байтах. Последний содержит отступ на 4 байта меньше. Это плохо?
Чтобы добавить оскорбления к травме, ученик решает зациклить, в то время как ввод может быть проанализирован как int. Решение без try / catch может выглядеть примерно так:
Но как это выглядит при использовании try / catch?
Блоки try / catch - это волшебный способ потратить впустую отступы, и мы до сих пор даже не знаем, почему это не удалось! Представьте, что чувствует человек, выполняющий отладку, когда код продолжает выполняться после серьезной логической ошибки, а не останавливается с красивой очевидной ошибкой исключения. Блоки try / catch - это проверка / исправление данных для ленивых людей.
Одна из меньших затрат заключается в том, что блоки try / catch действительно отключают определенные оптимизации: http://msmvps.com/blogs/peterritchie/archive/2007/06/22/performance-implications-of-try-catch-finally.aspx . Думаю, это тоже положительный момент. Его можно использовать для отключения оптимизаций, которые в противном случае могли бы нанести вред безопасным, нормальным алгоритмам передачи сообщений для многопоточных приложений, а также для выявления возможных состояний гонки;) Это единственный сценарий, который я могу придумать для использования try / catch. Даже у этого есть альтернативы.
источник
Int.Parse
в пользуInt.TryParse
.