В разделе С#, сколько из производительности попало в блок try, throw и catch

Прежде всего, отказ от ответственности: У меня есть опыт работы на других языках, но я все еще изучаю тонкости С#

В связи с проблемой... Я смотрю на некоторый код, который использует блоки try/catch таким образом, который касается меня. Когда вызывается процедура разбора, а не возвращает код ошибки, программист использовал следующую логику

catch (TclException e) {
  throw new TclRuntimeError("unexpected TclException: " + e.Message,e);
}  

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

выполните резервное копирование примерно на 6 уровней.

Я правильно понял, что все эти блоки catch/throw вызывают проблемы с производительностью или это разумная реализация в С#?

Ответы

Ответ 1

Бросок (а не улов) стоит дорого.

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

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

РЕДАКТИРОВАТЬ: Чтобы избежать двусмысленности:

Rethrow:

catch (SomeException) {
  throw;
}

Создать исключение из предыдущего объекта исключения, в котором все состояние состояния выполнения (в частности, трассировка стека) перезаписывается:

catch (SomeException e) {
  throw e;
}

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

catch (SomeException e) {
  throw new SomeException(e.Message);
}

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

Ответ 2

Это плохой дизайн на любом языке.

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

По-видимому, парень, который написал этот код, использовал коды ошибок, а затем переключился на исключения, фактически не понимая, как они работают. Исключения автоматически "выкручивают" стек, если на одном уровне нет улова.

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

Ответ 4

В общем, бросание исключения дорого стоит в .NET. Просто иметь блок try/catch/finally нет. Итак, да, существующий код плох с точки зрения производительности, потому что когда он бросает, он бросает 5-6 раздутых исключений, не добавляя никакого значения, просто позволяя исходному исключению естественно пузыриться 5-6 кадров стека.

Хуже того, существующий код действительно плохой с точки зрения дизайна. Одним из основных преимуществ обработки исключений (по сравнению с возвращаемыми кодами ошибок) является то, что вам не нужно проверять коды исключений/возврата везде (в стеке вызовов). Вам нужно только поймать их на небольшом количестве мест, которые вы на самом деле хотите обработать. Игнорирование исключения (в отличие от игнорирования кода возврата) не игнорирует и не скрывает проблему. Это просто означает, что он будет обрабатываться выше стека вызовов.

Ответ 5

Это не страшно само по себе, но нужно действительно наблюдать за гнездом.

Допустимый вариант использования таков:

Я низкоуровневый компонент, который может столкнуться с рядом различных ошибок, однако мой потребитель интересуется только конкретным типом исключения. Поэтому я могу это сделать:

catch(IOException ex)
{
    throw new PlatformException("some additional context", ex);
}

Теперь это позволяет пользователю делать:

try
{
    component.TryThing();
}
catch(PlatformException ex)
{
   // handle error
}

Да, я знаю, что некоторые люди скажут, но потребитель должен поймать IOException, но это зависит от того, насколько абстрактным является код потребления. Что, если Impl сохраняет что-то на диск, и у потребителя нет веских оснований думать, что их операция коснется диска? В таком сценарии нет смысла помещать эту обработку исключений в код потребления.

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

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

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

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

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

Главное правило, которое следует помнить при обсуждении исключений, состоит в том, что Исключения не должны возникать в нормальном потоке приложений (нормальное значение означает отсутствие ошибок). Все остальное вытекает из этого утверждения.

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

Ответ 6

Try/Catch/Throw медленнее - лучше будет проверять значение, прежде чем поймать его, но если вы полностью не сможете продолжить, вам лучше бросать и ловить только когда он рассчитывает. В противном случае проверка и протоколирование более эффективны.

Ответ 7

Если каждый слой стека просто бросает один и тот же тип с той же информацией, не добавляя ничего нового, тогда он совершенно абсурден.

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

Как правило, это плохая идея поймать и перебросить при любых обстоятельствах без уважительной причины. Это связано с тем, что как только будет найден блок catch, все блоки finally между броском и catch будут выполнены. Это должно произойти только в том случае, если исключение можно восстановить. Это нормально в этом случае, потому что улавливается определенный тип, поэтому автор кода (надеюсь) знает, что они могут безопасно отменять любые собственные изменения внутреннего состояния в ответ на этот конкретный тип исключения.

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

Ответ 8

Исключения выполняются медленно, старайтесь не использовать их.

См. ответ, который я дал здесь.

В принципе, Крис Брумме (который был в команде CLR) сказал, что они реализованы как исключения SEH, поэтому вы получаете большой успех, когда их бросают, должны пострадать от штрафов, когда они пузырятся через стек ОС. Это действительно отличная статья и подробно рассказывает о том, что происходит, когда вы бросаете исключение. например:.


Конечно, наибольшая стоимость исключения - это когда вы на самом деле бросаете один. Я вернусь к этому ближе к концу блога.


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


Однако существует серьезный долгосрочный проблема производительности с исключениями и это должно быть учтено в вашем решение.

Рассмотрим некоторые вещи, которые произойдет, когда вы выбросите исключение:

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

  • Пропустите цепочку обработчиков вверх по стеку, вызывая каждый обработчик дважды.

  • Компенсировать несоответствия между SEH, С++ и управляемыми исключения.

  • Выделите управляемый экземпляр Exception и запустите его конструктор. Скорее всего, это связано с поиском ресурсов для различной ошибки сообщения.

  • Возможно, совершите поездку через ядро ​​ОС. Часто беру аппаратное обеспечение исключение.

  • Сообщать об отложенных отладчиках, профилировщиках, векторных обработчиках исключений и других заинтересованных сторон.

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

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

Старая пословица, исключения должны использоваться только для исключительных обстоятельств, так же верно для С#, как и для любого другого языка.