Вопросы производительности для создания исключений

Я много раз сталкивался со следующим типом кода, и мне интересно, является ли это хорошей практикой (с точки зрения производительности) или нет:

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);
}

По сути, кодер делает то, что он включает исключение в пользовательское исключение и выдает его снова.

Как это отличается по производительности от следующих двух:

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw ex;
}

или

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw;
}

Оставляя в стороне какие-либо функциональные аргументы или аргументы наилучшей практики кодирования, есть ли разница в производительности между тремя подходами?

9.08.2008 20:01:09
8 ОТВЕТОВ
РЕШЕНИЕ

@Brad Tutterow

Исключение не теряется в первом случае, оно передается конструктору. В остальном я согласен с вами, но второй подход - очень плохая идея из-за потери трассировки стека. Когда я работал с .NET, я сталкивался со многими случаями, когда другие программисты делали именно это, и это безнадежно расстраивало меня, когда мне нужно было увидеть истинную причину исключения, а только обнаружить, что оно было переброшено из огромного блока try, где Теперь я понятия не имею, откуда возникла проблема.

Я также второй комментарий Брэда, что вы не должны беспокоиться о производительности. Этот вид микрооптимизации - УЖАСНАЯ идея. Если вы не говорите о создании исключения в каждой итерации цикла for, который выполняется в течение длительного времени, вы, скорее всего, не столкнетесь с проблемами производительности из-за использования вашего исключения.

Всегда оптимизируйте производительность, когда у вас есть показатели, которые указывают на то, что вам НЕОБХОДИМО оптимизировать производительность, а затем попадайте в те места, которые оказались виновником.

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

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

11
9.08.2008 21:17:35

Бросок в вашем первом примере имеет накладные расходы на создание нового объекта CustomException.

Повторный выброс в вашем втором примере вызовет исключение типа Exception.

Повторный выброс в вашем третьем примере вызовет исключение того же типа, который был выдан вашим «некоторым кодом».

Таким образом, второй и третий примеры используют меньше ресурсов.

0
9.08.2008 20:59:47

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

FxCop всегда рекомендует третий подход, а не второй, чтобы исходная трассировка стека не терялась.

Редактировать: Удалены вещи, которые были просто неправильно, и Майк был достаточно любезен, чтобы указать.

2
9.08.2008 21:33:28

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

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

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

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

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

Как примечание стороны:

Мне лично не нравится использование исключений (иерархий классов, производных от класса Exception) для реализации логики. Как в случае:

try {
        // something that will raise an exception almost half the time
} catch( InsufficientFunds e) {
        // Inform the customer is broke
} catch( UnknownAccount e ) {
        // Ask for a new account number
}
2
9.08.2008 21:06:33

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

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

0
29.11.2008 03:18:52

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

Я лично использую пользовательские исключения, если я хочу отделить определенные зависимости в коде. Например, у меня есть метод, который загружает данные из файла XML. Это может пойти не так по-разному.

Может произойти сбой при чтении с диска (FileIOException), пользователь может попытаться получить к нему доступ откуда-то, где ему запрещено (SecurityException), файл может быть поврежден (XmlParseException), данные могут быть в неправильном формате (DeserialisationException).

В этом случае вызывающему классу легче разобраться во всем этом, все эти исключения перебрасывают одно пользовательское исключение (FileOperationException), так что вызывающему не нужны ссылки на System.IO или System.Xml, но он все еще может Получите доступ, какая ошибка произошла через перечисление и любую важную информацию.

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

public bool Load(string filepath)
{
  if (File.Exists(filepath)) //Avoid throwing by checking state
  {
    //Wrap anyways in case something changes between check and operation
    try { .... }
    catch (IOException ioFault) { .... }
    catch (OtherException otherFault) { .... }
    return true; //Inform caller of success
  }
  else { return false; } //Inform caller of failure due to state
}
1
31.10.2011 14:06:13

Не делай

try
{
    // some code
}
catch (Exception ex) { throw ex; }

Как это потеряет трассировку стека.

Вместо этого сделайте:

try
{
    // some code
}
catch (Exception ex) { throw; }

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

2
16.08.2008 14:24:37
Небольшое дополнение - удалите ex, иначе вы создадите предупреждение о неиспользованной переменной. try {// некоторый код} catch (Exception) {throw; }
Dennis 24.04.2009 04:50:06

Подождите .... почему мы заботимся о производительности, если выдается исключение? Если только мы не используем исключения как часть обычного потока приложений (что WAYYYY против лучших практик).

Я видел только требования к производительности в отношении успеха, но не в отношении неудачи.

0
30.09.2008 12:56:02