Страницы

Поиск по вопросам

среда, 4 декабря 2019 г.

Нанооптимизация в цикле for

#c_sharp #clr


Например, есть массив с элементами.

int [] numbers = new int[] { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Length; ++i)
{
    Console.WriteLine(numbers[i]);
}



Открыв ILSpy, обнаружил что (++i)преинкремент стал постинкриментом(i++), хотя казалось
бы, должно быть наоборот.
number.Length высчитывается 1 раз или при каждой итерации??(по идее каждый раз, но
мало ли среда как-то это оптимизирует)
Есть ли смысл выносить условие в отдельную переменную перед циклом? 

    


Ответы

Ответ 1



Вы смотрите не туда. Реальной оптимизацией занимается JIT-компилятор, а он довольно умный. Для вашего кода, он произвёл следующий объектный код (разумеется, Release-режим и без отладчика): 00007FF88B8B04ED xor edi,edi ; i = 0 00007FF88B8B04EF movsxd rcx,edi 00007FF88B8B04F2 mov ecx,dword ptr [rsi+rcx*4+10h] ; ecx = numbers[i] 00007FF88B8B04F6 call 00007FF8E9C19E40 ; Console.WriteLine 00007FF88B8B04FB inc edi ; i++ 00007FF88B8B04FD cmp edi,5 ; if (i < 5) 00007FF88B8B0500 jl 00007FF88B8B04EF ; repeat Вы видите, что не только исчезла разница между пре- и пост-инкрементом, не только исчезло повторное чтение Length, а ещё оптимизатор смог понять, что длина равна константе 5. Поверьте, компиляторы справляются с нанооптимизациями куда лучше нас с вами. На уровне IL-кода разницы между пре- и постинкрементом нет*: IL_001e: ldloc.1 IL_001f: ldc.i4.1 IL_0020: add IL_0021: stloc.1 То, что ILSpy декомпилировал эту последовательность команд на C# как постинкремент, это исключительно для удобства читателей (постинкремент привычнее). Ну и финальный совет: нет никаких письменных правил (кроме личного опыта) по поводу того, что быстро, а что медленно. Хуже того, любые «правила» с выходом новой версии компилятора станут скорее всего неправильными: оптимизаторы улучшаются каждый день. Поэтому: старайтесь писать так, чтобы ваш код был читаем, не увлекайтесь нанооптимизациями, профилируйте ваш код регулярно и устраняйте bottleneck'и. *Как правильно подсказывает в комментариях @PetSerAl, разница между пре- и постинкрементом в C# (в отличие от C++) состоит лишь в том, какое значение возвращается выражением. Поэтому для случая, когда результатом инкремента никто не пользуется, их смысл всегда одинаков (для любого типа, не только для int).

Комментариев нет:

Отправить комментарий