Вопрос-ответ

Difference between declaring variables before or in loop?

Разница между объявлением переменных до или в цикле?

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

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

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

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

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

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

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

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

Переведено автоматически
Ответ 1

Что лучше, a или b?

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

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

Ответ 2

Что ж, я прогнал ваши примеры A и B по 20 раз каждый, выполнив цикл 100 миллионов раз.(JVM - 1.5.0)

A: среднее время выполнения: 0,074 сек

B: среднее время выполнения: 0,067 сек

К моему удивлению, B был немного быстрее. При нынешней скорости компьютеров трудно сказать, сможете ли вы точно измерить это. Я бы также закодировал это способом A, но я бы сказал, что это действительно не имеет значения.

Ответ 3

Это зависит от языка и точного использования. Например, в C # 1 это не имело никакого значения. В C # 2, если локальная переменная фиксируется анонимным методом (или лямбда-выражением в C # 3), это может иметь очень существенное значение.

Пример:

using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
List<Action> actions = new List<Action>();

int outer;
for (int i=0; i < 10; i++)
{
outer = i;
int inner = i;
actions.Add(() => Console.WriteLine("Inner={0}, Outer={1}", inner, outer));
}

foreach (Action action in actions)
{
action();
}
}
}

Вывод:

Inner=0, Outer=9
Inner=1, Outer=9
Inner=2, Outer=9
Inner=3, Outer=9
Inner=4, Outer=9
Inner=5, Outer=9
Inner=6, Outer=9
Inner=7, Outer=9
Inner=8, Outer=9
Inner=9, Outer=9

Разница в том, что все действия фиксируют одну и ту же outer переменную, но у каждого есть своя отдельная inner переменная.

Ответ 4

Следующее - это то, что я написал и скомпилировал в .NET.

double r0;
for (int i = 0; i < 1000; i++) {
r0 = i*i;
Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
double r1 = j*j;
Console.WriteLine(r1);
}

Это то, что я получаю от .NET Reflector когда CIL возвращается обратно в код.

for (int i = 0; i < 0x3e8; i++)
{
double r0 = i * i;
Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
double r1 = j * j;
Console.WriteLine(r1);
}

Таким образом, после компиляции оба выглядят абсолютно одинаково. В управляемых языках код преобразуется в CL / байтовый код, а во время выполнения он преобразуется в машинный язык. Таким образом, в машинном языке double может даже не создаваться в стеке. Это может быть просто регистр, поскольку код отражает, что это временная переменная для WriteLine функции. Существует целый набор правил оптимизации только для циклов. Так что обычному пользователю не стоит беспокоиться об этом, особенно в управляемых языках. Бывают случаи, когда вы можете оптимизировать код управления, например, если вам нужно объединить большое количество строк, используя только string a; a+=anotherstring[i] против использования StringBuilder. Существует очень большая разница в производительности между обоими. Существует множество таких случаев, когда компилятор не может оптимизировать ваш код, потому что он не может определить, что предназначено в большей области видимости. Но это может в значительной степени оптимизировать базовые вещи для вас.

java performance