Подтвердить что ты не робот

Есть ли разница в производительности между() и while()?

Или все о семантике?

4b9b3361

Ответ 1

Короткий ответ: нет, они точно такие же.

Предположим, что теоретически это зависит от компилятора; действительно сломанный может сделать что-то немного другое, но я был бы удивлен.

Просто для удовольствия здесь два варианта, которые скомпилируются с точностью до одного и того же кода сборки для меня, используя x86 gcc версию 4.3.3, поставляемую с Ubuntu. Вы можете проверить сборку, созданную в финальном двоичном файле, с objdump в linux.

int main()
{
#if 1
    int i = 10;
    do { printf("%d\n", i); } while(--i);
#else
    int i = 10;
    for (; i; --i) printf("%d\n", i);
#endif
}

РЕДАКТИРОВАТЬ: Вот пример "апельсинов с апельсинами" в примере цикла, который также сводится к одному и тому же:

    while(i) { printf("%d\n", i); --i; }

Ответ 2

Если ваши петли for и while выполняют одни и те же вещи, машинный код, сгенерированный компилятором, должен быть (почти) одинаковым.

Например, в некоторых тестах, которые я сделал несколько лет назад,

for (int i = 0; i < 10; i++)
{
...
}

и

int i = 0;
do
{
  ...
  i++;
}
while (i < 10);

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

Ответ 3

Нет семантической разницы, нет необходимости компилировать разницу. Но это зависит от компилятора. Поэтому я попробовал с g++ 4.3.2, CC 5.5 и xlc6.

g++, CC были идентичны, xlc не был

Разница в xlc была в записи начального цикла.

extern int doit( int );
void loop1( ) {
  for ( int ii = 0; ii < 10; ii++ ) {
    doit( ii );
  }
}

void loop2() {
  int ii = 0; 
  while ( ii < 10 ) {
    doit( ii );
    ii++;
  }
}

XLC OUTPUT

.loop2:                                 # 0x00000000 (H.10.NO_SYMBOL)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    st      r3,64(SP)
    l       r3,64(SP)  ### DIFFERENCE ###
    cmpi    0,r3,10
    bc      BO_IF_NOT,CR0_LT,__L40
...
enter code here
.loop1:                                 # 0x0000006c (H.10.NO_SYMBOL+0x6c)
    mfspr   r0,LR
    stu     SP,-80(SP)
    st      r0,88(SP)
    cal     r3,0(r0)
    cmpi    0,r3,10    ### DIFFERENCE ###
    st      r3,64(SP)
    bc      BO_IF_NOT,CR0_LT,__La8
...

Ответ 4

Объем переменной в тесте цикла while шире, чем область переменных, объявленных в заголовке цикла for.

Поэтому, если есть последствия для производительности в качестве побочного эффекта сохранения переменной дольше, тогда будут последствия производительности при выборе между while и циклом for (а не обертывание while в {}, чтобы уменьшить объем его переменных).

Примером может быть параллельный набор, который подсчитывает количество итераторов, ссылающихся на него, и если существует более одного итератора, он применяет блокировку для предотвращения одновременной модификации, но поскольку оптимизация исключает блокировку, если к ней относится только один итератор, Если у вас тогда было две петли for в функции с использованием именованных именованными именами в одном и том же контейнере, быстрый путь был бы выполнен, но с двумя циклами while будет выполняться медленный путь. Точно так же могут иметь место последствия для производительности, если объекты большие (больше кеш-трафика) или использование системных ресурсов. Но я не могу придумать настоящего примера, который я когда-либо видел, где бы это имело значение.

Ответ 5

Компиляторы, которые оптимизируются с использованием разворачивания цикла, вероятно, будут делать это только в случае for-loop.

Ответ 6

Оба эквивалентны. Это вопрос семантики.

Единственное различие может заключаться в do... while construct, где вы откладываете оценку состояния до тех пор, пока после тела, и, таким образом, не сможете сохранить 1 оценку.

i = 1; do { ... i--; } while( i > 0 ); 

в отличие от

for(  i = 1; i > 0; --i )
{ ....
}  

Ответ 7

Я пишу компиляторы. Мы собираем весь "структурированный" поток управления (if, while, for, switch, do... while) в условные и безусловные ветки. Затем мы анализируем граф потока управления. Так как компилятор C должен иметь дело с общим goto в любом случае, проще всего сводить все к инструкциям ветки и условной ветки, а затем не забудьте хорошо обработать этот случай. (Компилятор C должен делать хорошую работу не только по рукописному коду, но и по автоматически сгенерированному коду, у которого может быть много, много операторов goto.)

Ответ 8

Нет. Если они выполняют эквивалентные вещи, они будут скомпилированы в один и тот же код, как вы говорите, о семантике. Выберите тот, который лучше всего отражает то, что вы пытаетесь выразить.

Ответ 9

В идеале это должно быть одно и то же, но в конечном итоге это зависит от вашего компилятора/интерпретатора. Разумеется, вы должны измерить или просмотреть сгенерированный код сборки.

Доказательство того, что может быть разница: эти строки создают другой код сборки с использованием cc65.

for (; i < 1000; ++i);   
while (i < 1000) ++i;

Ответ 10

В Atmel ATMega while() работает быстрее, чем для(). Почему это объясняется в AVR035: эффективное C-кодирование для AVR.

P.S. Оригинальная платформа не упоминалась в вопросе.

Ответ 11

continue ведет себя по-разному в для и , а: в для, он изменяет счетчик в while, обычно это не

Ответ 12

Чтобы добавить еще один ответ: по моему опыту, оптимизация программного обеспечения похожа на большую, густую бороду, сбритую мужчиной.

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

В последнем случае разница между for() и while() может, но, вероятно, не изменится.

P.S. Программисты, которых я знаю (кто все очень хорош, и я подозреваю, что это репрезентативный пример), в основном идут на него с другого направления.

Ответ 13

Они такие же, как и производительность. Я обычно использую while, ожидая изменения состояния (например, ожидание заполнения буфера) и for при обработке нескольких дискретных объектов (например, через каждый элемент в коллекции).

Ответ 14

В некоторых случаях есть разница.

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

Ответ 15

Является ли while() быстрее/медленнее, чем for()? Давайте рассмотрим несколько вещей об оптимизации:

  • Авторы-компиляторы работают очень интенсивно, чтобы сбривать циклы, имея меньше вызовов для перехода, сравнения, увеличения и других типов команд, которые они генерируют.

  • С другой стороны, инструкции вызова потребляют много величин больше циклов, но компилятор почти бессилен сделать что-либо, чтобы удалить их.

  • Как программисты, мы пишем много вызовов функций, некоторые из них, потому что мы имеем в виду некоторые из них, потому что мы ленивы, а некоторые из-за того, что компилятор их проскальзывает, не будучи очевидным.

  • В большинстве случаев это не имеет значения, потому что аппаратное обеспечение настолько быстрое, и наши рабочие места настолько малы, что компьютер похож на собаку гончей, которая волнует ее пищу и просит больше.

  • Иногда, однако, задание достаточно велико, что производительность является проблемой.

  • Что нам делать тогда? Где больший выигрыш?

    • Получение компилятора для сбривания нескольких циклов цикла и т.д.
    • Найти вызовы функций, которые не выполняются - действительно, нужно сделать так много?
  • Компилятор не может использовать последний. Только мы, программисты, можем.

  • Нам нужно научиться или научиться тому, как это сделать. Это не происходит естественно. Мы врожденно склонны делать неправильные догадки, а затем делаем ставку на них. Получение лучших алгоритмов - это начало, но только начало. Наши учителя должны учить это, если они действительно знают, как.

  • Профилисты - это начало. Я делаю это.

Апокрифическая цитата Вилли Саттона, когда его спросили Почему вы грабите банки?:
Потому что там, где деньги.

Если вы хотите сохранить циклы, узнайте, где они находятся.

Ответ 16

Вероятно, только стиль кодирования.

  • если вы знаете количество итераций.
  • если вы не знаете количество итераций.