Сколько стоит переоценка исключения? - PullRequest
12 голосов
/ 22 июня 2011

Это

try
  DoSomethingThatMightThrowAnException;
except
  on E : ESyntaxError do
    begin
    if (E.ErrorCode = errMissingBracket) then
      HandleError
    else
      raise;
    end;
end;

медленнее, чем это?

try
  DoSomethingThatMightThrowAnException;
except
  on E : EMissingBracketSyntaxError do
    begin
    HandleError;
    end;
end;

Какая разница? Это имеет значение? Обратите внимание, что это может происходить несколько раз в стеке вызовов.

Ответы [ 4 ]

2 голосов
/ 22 июня 2011

Какая разница?

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

Это имеет значение? Обратите внимание, что это может происходить несколько раз через стек вызовов.

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

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

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

т.е. вместо:

begin
  try
    //Do1
    //Do2 (possibly raising an exception that you can handle)
    //Do3
    //Do4
  except
    //Dealing with main-line cases in exception handlers is
    //very bad, leading to difficult to read code in the future.
  end;
end;

Скорее напишите:

begin
  //Do1
  //LDo2Result := Do2
  //NOTE: Do2 can still raise exceptions in EXCEPTIONAL situations.
  //  But for "main-line" use-case scenarios should rather return explicit 
  //  results that can be handled.
  if LDo2Result = d2rNoErrors then
  begin
    //Do3
    //Do4
  end;
  if LDo2Result = d2rBracketMissing then
  begin
    //DoX
  end;
end;

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

1 голос
/ 22 июня 2011

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

1 голос
/ 22 июня 2011

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

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

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

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

0 голосов
/ 22 июня 2011

Я быстро взглянул на ассемблер, который компилятор выбрасывает для приведенных выше фрагментов кода. Оказывается, что байты сразу после jmp @HandleOnExeption содержат данные, такие как указатели на класс исключений, которые вы используете в предложениях on (если есть).

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

Я подозреваю, что HandleOnException System.pas уже делает call @IsClass и передает исключение, если подходящего обработчика не найдено, поэтому, если вы используете on e:Exception и повторно поднимаете, это добавит небольшой код и сделает два дополнительные звонки:

  • один назад в ваш раздел обработки исключений (во всех случаях)
  • один call @RaiseAgain (в случаях, когда исключение повторно вызывается)

Итак, есть разница. Незначительный, но все же, он там.

...