Разница между объявлением переменных до или в цикле? - PullRequest
304 голосов
/ 02 января 2009

Я всегда задавался вопросом, имеет ли какое-либо значение (производительность), вообще говоря, объявление одноразовой переменной перед циклом, в отличие от многократного внутри цикла? Пример (совершенно бессмысленный) на Java:

a) объявление перед циклом:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

b) объявление (многократно) внутри цикла:

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

Какой из них лучше, a или b ?

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

Редактировать: Меня особенно интересует случай с Java.

Ответы [ 25 ]

0 голосов
/ 13 июля 2016

это лучшая форма

double intermediateResult;
int i = byte.MinValue;

for(; i < 1000; i++)
{
intermediateResult = i;
System.out.println(intermediateResult);
}

1) таким способом объявляется один раз раз как переменная, а не каждая за цикл. 2) Назначение это более толстый, чем все другие варианты. 3) Таким образом, правило bestpractice - это любое объявление вне итерации для.

0 голосов
/ 04 апреля 2016

Я тестировал JS с Node 4.0.0, если кому-то интересно. Объявление вне цикла привело к повышению производительности примерно на 0,5 мс в среднем за 1000 испытаний со 100 миллионами итераций цикла на испытание. Так что я собираюсь сказать: «Вперед и напиши это наиболее читаемым / поддерживаемым способом, который B, IMO». Я бы поместил свой код в скрипку, но я использовал модуль Node для повышения производительности. Вот код:

var now = require("../node_modules/performance-now")

// declare vars inside loop
function varInside(){
    for(var i = 0; i < 100000000; i++){
        var temp = i;
        var temp2 = i + 1;
        var temp3 = i + 2;
    }
}

// declare vars outside loop
function varOutside(){
    var temp;
    var temp2;
    var temp3;
    for(var i = 0; i < 100000000; i++){
        temp = i
        temp2 = i + 1
        temp3 = i + 2
    }
}

// for computing average execution times
var insideAvg = 0;
var outsideAvg = 0;

// run varInside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varInside()
    var end = now()
    insideAvg = (insideAvg + (end-start)) / 2
}

// run varOutside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varOutside()
    var end = now()
    outsideAvg = (outsideAvg + (end-start)) / 2
}

console.log('declared inside loop', insideAvg)
console.log('declared outside loop', outsideAvg)
0 голосов
/ 02 января 2009

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

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

РЕДАКТИРОВАТЬ: Джон Скит сделал очень хорошую мысль, показав, что объявление переменной внутри цикла может иметь фактическое семантическое отличие.

0 голосов
/ 06 марта 2015

Это интересный вопрос. Исходя из моего опыта, при обсуждении этого вопроса для кода возникает главный вопрос:

Есть ли причина, по которой переменная должна быть глобальной?

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

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

0 голосов
/ 11 мая 2010

A) безопаснее, чем B) ......... Представьте себе, если вы инициализируете структуру в цикле, а не int или float, что тогда?

как

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

Вы наверняка столкнетесь с проблемами утечки памяти! Поэтому я полагаю, что «А» безопаснее, а «В» уязвим для накопления памяти, особенно при работе с библиотеками с закрытым исходным кодом. Вы можете проверить использование инструмента «Valgrind» в Linux, в частности, вспомогательного инструмента «Helgrind».

...