В случае кода, в котором вы должны выполнить очистку ресурса перед выходом из функции, существует ли существенная разница в производительности между этими двумя способами.
Очистка ресурса перед каждым оператором возврата
void func() { login(); bool ret = dosomething(); if(ret == false) { logout(); return; } ret = dosomethingelse(); if(ret == false) { logout(); return; } dootherstuff(); logout(); }
Очистка ресурса в блоке finally
void func() { login(); try { bool ret = dosomething(); if(ret == false) return; ret = dosomethingelse(); if(ret == false) return; dootherstuff(); } finally { logout(); } }
Я провел несколько базовых тестов в примерах программ, и, похоже, нет особой разницы. Я очень предпочитаю finally
способ сделать это, но мне было интересно, не приведет ли это к снижению производительности в большом проекте.
java
performance
efficiency
user93353
источник
источник
if(!cond)
, то я сделал это с помощью Java. В C ++, это, как я пишу код оба булевых , а также для других типов - то естьint x;
if(!x)
. Поскольку Java позволяет мне использовать это только дляbooleans
, я полностью прекратил использоватьif(cond)
&if(!cond)
в Java.(someIntValue != 0)
не сравнивать, а не оценивать логические значения. Это пахнет для меня, и я немедленно делаю рефакторинг, когда вижу его в дикой природе.Ответы:
Как указано в разделе Как медленно работают исключения Java? Можно видеть, что медлительность
try {} catch {}
находится в пределах самого исключения.Создание исключения приведет к извлечению всего стека вызовов из среды выполнения, и именно в этом и заключается стоимость. Если вы не создаете исключение, это лишь очень незначительно увеличение времени.
В примере, приведенном в этом вопросе, нет никаких исключений, не следует ожидать замедления при их создании - они не создаются. Вместо этого то, что здесь, является
try {} finally {}
обработкой освобождения ресурса в блоке finally.Таким образом, чтобы ответить на вопрос, нет, в
try {} finally {}
структуре, которая не использует исключения, нет реальных затрат времени выполнения (это не неслыханно, как видно). Что может быть дорогостоящим, так это время обслуживания, когда кто-то читает код и видит этот нетипичный стиль кода, и кодировщик должен решить, что в этом методе происходит что-то еще после того,return
как он возвращается к предыдущему вызову.Как уже упоминалось, техническое обслуживание является аргументом для обоих способов сделать это. Для протокола, после рассмотрения, мои предпочтения будут окончательным подходом.
Подумайте о том, сколько времени нужно обучить новой языковой структуре. Видение
try {} finally {}
- это не то, что часто можно увидеть в коде Java, и поэтому оно может сбить людей с толку. Существует время, необходимое для изучения немного более сложных структур в Java, чем то, что люди знакомы с просмотром.finally {}
Блок всегда работает. И именно поэтому вы должны его использовать. Также учтите время обслуживания отладки не-окончательного подхода, когда кто-то забывает включить выход в нужный момент, или вызывает его в неподходящее время, или забывает вернуться / выйти после вызова, чтобы он вызывался дважды. При этом существует так много возможных ошибок, которыеtry {} finally {}
невозможно использовать.При взвешивании этих двух затрат во время обслуживания дорого не использовать
try {} finally {}
подход. В то время как люди могут узнать, сколько дробных миллисекунд или дополнительных инструкций jvmtry {} finally {}
блок сравнивается с другой версией, нужно также учитывать часы, потраченные на отладку, не идеального способа решения проблемы выделения ресурсов.Сначала пишите обслуживаемый код, желательно таким образом, чтобы избежать ошибок позже.
источник
/programming/299068/how-slow-are-java-exceptions
Принятый ответ на этот вопрос показывает, что перенос вызова функции в блок try catch стоит менее 5% по сравнению с простым вызовом функции. Фактически, выброс и перехват исключительной ситуации привел к тому, что время выполнения увеличилось в 66 раз по сравнению с простым вызовом функции. Поэтому, если вы ожидаете, что дизайн исключений будет генерироваться регулярно, тогда я постараюсь избежать его (в правильно профилированном критичном для производительности коде), однако, если исключительная ситуация встречается редко, это не имеет большого значения.
источник
Вместо оптимизации - подумайте о том, что делает ваш код.
Добавление блока finally является другой реализацией - это означает, что вы будете выходить из системы при каждом исключении.
В частности - если при входе в систему выдается исключение, поведение вашей второй функции будет отличаться от вашего первого.
Если вход в систему и выход из нее на самом деле не являются частью поведения функции, то я бы предложил, чтобы метод хорошо выполнял одну вещь:
и должен быть в функции, которая уже инкапсулирована в контексте, который управляет входом / выходом из системы, так как они кажутся принципиально отличными от того, что делает ваш основной код.
Ваш пост помечен как Java, с которым я не очень знаком, но в .net я бы использовал блок using для этого:
то есть:
И у контекста входа есть метод Dispose, который будет выходить из системы и очищать ресурсы.
Изменить: я на самом деле не ответил на вопрос!
У меня нет измеримых доказательств, но я не ожидал бы, что это будет дороже или, конечно, не будет достаточно дорого для того, чтобы оно было достойно преждевременной оптимизации.
Я собираюсь оставить остальную часть моего ответа, потому что, хотя и не отвечаю на вопрос, я думаю, что это полезно для ОП.
источник
using
конструкцию, предполагая, что рассматриваемый ресурс реализуетAutoCloseable
интерфейс.ret
переменную, которая просто назначается дважды для проверки на одну строку позже. Сделай этоif (dosomething() == false) return;
.ret2 = doSomethingElse(ret1)
, но это не относится к вопросу, поэтому он был удален.if (dosomething() == false) ...
плохой код Используйте более интуитивныйif (!dosomething()) ...
Предположение: вы разрабатываете на C # код.
Быстрый ответ заключается в том, что при использовании блоков try / finally не наблюдается существенного снижения производительности. Когда вы бросаете и ловите исключения, производительность падает.
Чем дольше ответ, тем лучше для себя. Если вы посмотрите на сгенерированный базовый код CIL ( например, рефлектор red-gate, то вы сможете увидеть сгенерированные базовые инструкции CIL и увидеть влияние таким образом.
источник
Как и другие уже отмечалось, Ttese код будет иметь разные результаты, если либо
dosomethingelse
илиdootherstuff
выбросить исключение.И да, любой вызов функции может вызвать исключение, по крайней мере, a
StackOVerflowError
! Несмотря на то, что очень редко можно обрабатывать их правильно (так как любая вызываемая функция очистки, вероятно, будет иметь такую же проблему, в некоторых случаях (например, при реализации блокировок), важно даже правильно обработать это ...источник