Что ж, здесь трудно объяснить всю логику, лежащую в основе цикла.
Компилятор сделает удивительные вещи для вас, чтобы оптимизировать циклы, поэтому не имеет значения, используете ли вы while
илиfor
потому что компилятор все равно будет переводиться на ассемблер.
Чтобы иметь более глубокое понимание, вы должны изучить некоторый ассемблер и узнать, как работает базовый процессор, как он читает инструкции и как он их обрабатывает.
Чтобы улучшить конвейеризацию, лучше размещать операторы с одинаковыми переменными вдали друг от друга.Таким образом, пока вычисляется один оператор, процессор может взять следующий оператор, если он не зависит от первого, и начать его вычисление.
Например:
a=0;
b=3;
c=5;
m=8;
i=0;
while(i<10){
a=a+b*c;
b=b*10+a;
m=m*5;
i++;
}
У нас есть зависимостьздесь между a
и b
, а утверждения находятся рядом друг с другом.Но мы видим, что m
и i
не зависят от остальных, поэтому мы можем сделать:
a=0;
b=3;
c=5;
m=8;
i=0;
while(i<10){
a=a+b*c;
m=m*5;
i++;
b=b*10+a;
}
Итак, пока вычисляется a
, мы можем начать вычислять m
и i
.В большинстве случаев компилятор обнаруживает это и делает это автоматически (это переупорядочение кода вызова).Иногда для небольших циклов компилятор копирует и вставляет код внутри цикла столько раз, сколько это необходимо, потому что быстрее не иметь управляющих переменных.
Я предлагаю, чтобы компилятор позаботился об этих вещах исосредоточиться на затратах на алгоритмы, которые вы используете, лучше сократить с O (n!) до O (logn) , чем проводить микрооптимизацию внутри циклов.
Обновление в соответствии с измененным вопросом
Что ж, зависимости должны быть зависимостями записи / записи или чтения / записи.Если это зависимость чтения / чтения, то здесь нет проблем (потому что значение не меняется).Взгляните на [Data Dependency article] (http://en.wikipedia.org/wiki/Data_dependency).
В вашем примере нет разницы между двумя кодами, m
зависит от c
и b
, но эти дваникогда не пишутся, поэтому компилятор знает их значение до попадания в цикл. Это называется зависимостью чтения / чтения, и это не сама зависимость.
Если вы написали:
...
m=c+GetAvarage(a);
...
Тогда у нас будет зависимость записи / чтения (мы должны записать в a
, а затем прочитать из a
, поэтому мы должны ждать, пока не будет вычислено a
), и оптимизация, которую вы сделали, будет хорошей.
Но еще раз, компилятор делает это для вас и многих других вещей. Трудно сказать, что микрооптимизация в коде высокого уровня окажет реальное влияние на код ассемблера, потому чтовозможно, компилятор делает это уже для вас, или, может быть, переупорядочивает код для вас, или, может быть, делает тысячу других вещей лучше, чем мы можем представить на первый взгляд.
Но в любом случаеу, это хорошо, просто знать, как все работает под ковром:)
Обновление, чтобы добавить некоторые ссылки Посмотрите на эти ссылки, чтобы лучше понять, что компилятор может сделать дляулучшить производительность вашего кода:
Разматывание петли
Анализ зависимостей
Автоматическое распараллеливание
Векторизация