Что Быстрее While (True) Или For (;;)?

В сырых произведениях разных авторов я видел разные версии вечного цикла.

Чаще всего мне попадалось следующее:

  
  
  
  
  
  
   

while (true) { .

}

И

for (;;) { .

}

Поскольку каждый защищал «свой вечный цикл» как свой, я решил разобраться в нем.

Кто пишет более оптимальный код? Я написал 2 источника: пока.

с:

#include <stdio.h> int main (int argc, char* argv[]) { while(1){ printf("1\n"); } }

для.

c:

#include <stdio.h> int main (int argc, char* argv[]) { for(;;){ printf("1\n"); } }

Собрал их:

$ gcc -O3 while.c -o while.o3 $ gcc -O2 while.c -o while.o2 $ gcc -O1 while.c -o while.o1 $ gcc -O3 for.c -o for.o3 $ gcc -O2 for.c -o for.o2 $ gcc -O1 for.c -o for.o1

И разобрал его.

Если вам лень читать книги сборочных списков, вы можете прокрутить страницу вниз.

Собственно списки:

$ objdump -d .

/while.o3 .

0000000000400430 <main>: 400430: 48 83 ec 08 sub $0x8,%rsp 400434: 0f 1f 40 00 nopl 0x0(%rax) 400438: bf d4 05 40 00 mov $0x4005d4,%edi 40043d: e8 be ff ff ff callq 400400 <puts@plt> 400442: eb f4 jmp 400438 <main+0x8> .

$ objdump -d .

/while.o2 .

0000000000400430 <main>: 400430: 48 83 ec 08 sub $0x8,%rsp 400434: 0f 1f 40 00 nopl 0x0(%rax) 400438: bf d4 05 40 00 mov $0x4005d4,%edi 40043d: e8 be ff ff ff callq 400400 <puts@plt> 400442: eb f4 jmp 400438 <main+0x8> .

$ objdump -d .

/while.o1 .

000000000040051c <main>: 40051c: 48 83 ec 08 sub $0x8,%rsp 400520: bf d4 05 40 00 mov $0x4005d4,%edi 400525: e8 d6 fe ff ff callq 400400 <puts@plt> 40052a: eb f4 jmp 400520 <main+0x4> .

$ objdump -d .

/for.o1 .

000000000040051c <main>: 40051c: 48 83 ec 08 sub $0x8,%rsp 400520: bf d4 05 40 00 mov $0x4005d4,%edi 400525: e8 d6 fe ff ff callq 400400 <puts@plt> 40052a: eb f4 jmp 400520 <main+0x4> .

$ objdump -d .

/for.o2 .

0000000000400430 <main>: 400430: 48 83 ec 08 sub $0x8,%rsp 400434: 0f 1f 40 00 nopl 0x0(%rax) 400438: bf d4 05 40 00 mov $0x4005d4,%edi 40043d: e8 be ff ff ff callq 400400 <puts@plt> 400442: eb f4 jmp 400438 <main+0x8> .

$ objdump -d .

/for.o3 0000000000400430 <main>: 400430: 48 83 ec 08 sub $0x8,%rsp 400434: 0f 1f 40 00 nopl 0x0(%rax) 400438: bf d4 05 40 00 mov $0x4005d4,%edi 40043d: e8 be ff ff ff callq 400400 <puts@plt> 400442: eb f4 jmp 400438 <main+0x8>



Давайте разберемся на пальцах

Различные оптимизации не повлияли на реализацию цикла while (true) — он всегда выполнял 3 команды: mov, callq и jmp. Также оптимизации не затронули реализацию for — она тоже всегда состояла из 3-х команд: mov, callq, jmp. mov, callq и jmp ничем не отличались друг от друга.

Длина команд в байтах не меняется во всех 6 случаях.

Между реализациями есть лишь небольшая разница -O1 и -O2/-O3 jmp выполнялся на main+4, а не на main+8, но учитывая, что это статический адрес (как видно из ассемблерного кода), он тоже не влияет на производительность.

Хотя.

а вдруг страницы памяти разные, ведь насколько я знаю, перемещения между разными страницами памяти в x86 (и amd64) требуют дополнительных усилий со стороны процессора! Давай выясним: 400438/4096 = 97,763183594 400520/4096 = 97,783203125 Оно пролетело мимо.

Страница памяти только одна.

Да, это страница 97 виртуальной памяти виртуального адресного пространства процесса.

Но это именно то, что нам нужно.



Нижняя граница

while (true) и for (;;) идентичны по производительности друг другу и любым оптимизациям -Ox. Так что если вас спросят, какой из них быстрее, смело отвечайте, что «for (;;)» — 8 символов писать быстрее, чем « while (true)» — 12 символов.

Для тех, кто не верит, что без -Ox будет то же самое:

$ gcc while.c -o while.noO $ objdump -d while.noO .

40052b: bf e4 05 40 00 mov $0x4005e4,%edi 400530: e8 cb fe ff ff callq 400400 <puts@plt> 400535: eb f4 jmp 40052b <main+0xf> .

$ gcc for.c -o for.noO $ objdump -d for.noO .

40052b: bf e4 05 40 00 mov $0x4005e4,%edi 400530: e8 cb fe ff ff callq 400400 <puts@plt> 400535: eb f4 jmp 40052b <main+0xf> .



P.S. Разумеется, все это будет справедливо для компилятора «gcc версии 4.7.2 (Debian 4.7.2-5)».

Теги: #C++ #C++ # while #for #GCC #Assembler #objdump #C++ #C++

Вместе с данным постом часто просматривают: