Я сделал свою домашнюю работу и обнаружил неоднократные заверения в том, что на производительность не влияет, объявляете ли вы свои переменные внутри или вне цикла for, и на самом деле он компилируется в тот же самый MSIL. Но я тем не менее возился с этим и обнаружил, что перемещение объявлений переменных внутри цикла действительно приводит к значительному и постоянному приросту производительности.
Я написал небольшой тестовый класс для консоли, чтобы измерить этот эффект. Я инициализирую статический double[]
массив items, и два метода выполняют циклические операции с ним, записывая результаты в статический double[]
массив буфер. Первоначально мои методы были теми, с которыми я заметил разницу, а именно величину вычисления комплексного числа. Запустив их для массива items длиной 1000000 100 раз, я получил постоянно меньшее время выполнения для того, в котором переменные (6 переменных double
) находились внутри цикла: например, 32,83±0. ,64 мс против 43,24±0,45 мс на старой конфигурации с Intel Core 2 Duo @2,66 ГГц. Я пробовал выполнять их в другом порядке, но это не повлияло на результаты.
Потом я понял, что вычисление величины комплексного числа — это далеко не минимальный рабочий пример, и протестировал два гораздо более простых метода:
static void Square1()
{
double x;
for (int i = 0; i < buffer.Length; i++) {
x = items[i];
buffer[i] = x * x;
}
}
static void Square2()
{
for (int i = 0; i < buffer.Length; i++) {
double x;
x = items[i];
buffer[i] = x * x;
}
}
С ними результаты оказались обратными: объявление переменной вне цикла оказалось более благоприятным: 7,07±0,43 мс для Square1()
v 12,07±0,51 мс для Square2()
.
Я не знаком с ILDASM, но я разобрал два метода, и единственная разница, похоже, заключается в инициализации локальных переменных:
.locals init ([0] float64 x,
[1] int32 i,
[2] bool CS$4$0000)
in Square1()
v
.locals init ([0] int32 i,
[1] float64 x,
[2] bool CS$4$0000)
в Square2()
. В соответствии с ним, что stloc.1
в одном, то stloc.0
в другом, и наоборот. В более длинных кодах вычисления сложной величины MSIL даже размер кода различался, и я видел stloc.s i
в коде внешней декларации, где было stloc.0
во внутренней коде декларации.
Так как же это может быть? Я что-то упускаю из виду или это реальный эффект? Если это так, то это может существенно повлиять на производительность длинных циклов, поэтому я думаю, что это заслуживает некоторого обсуждения.
Ваши мысли очень ценятся.
РЕДАКТИРОВАТЬ: Единственное, что я упустил из виду, это проверить его на нескольких компьютерах перед публикацией. Я запустил его на i5, и результаты для двух методов почти идентичны. Приношу свои извинения за столь вводящее в заблуждение наблюдение.