Подтвердить что ты не робот

Какова стоимость ререйза исключения?

Это

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;

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

Какую разницу можно ожидать?

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

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

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

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

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

т.е. вместо:

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;

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

Ответ 3

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

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

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

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

Ответ 4

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