ในขณะที่ (1) สำหรับ (;;) มีความแตกต่างความเร็วหรือไม่


154

รุ่นยาว ...

เพื่อนร่วมงานยืนยันในวันนี้หลังจากเห็นการใช้งานของฉันwhile (1)ในสคริปต์ Perl ที่for (;;)เร็วขึ้น ฉันแย้งว่าพวกเขาควรจะเหมือนกันโดยหวังว่าล่ามจะปรับความแตกต่างให้เหมาะสม ฉันตั้งค่าสคริปต์ที่จะเรียกใช้ 1,000,000,000 สำหรับการวนซ้ำวนซ้ำและในขณะเดียวกันก็วนซ้ำและบันทึกเวลาระหว่างกัน ฉันไม่พบความแตกต่างที่เห็นคุณค่า เพื่อนร่วมงานของฉันบอกว่าศาสตราจารย์คนหนึ่งบอกเขาว่าการwhile (1)เปรียบเทียบกำลังดำเนินการอยู่1 == 1และfor (;;)ไม่ใช่ เราทำการทดสอบซ้ำกับ 100x จำนวนการวนซ้ำด้วย C ++ และความแตกต่างนั้นเล็กน้อย อย่างไรก็ตามเป็นตัวอย่างที่แสดงให้เห็นว่าโค้ดที่คอมไพล์ได้เร็วขึ้นสามารถเทียบกับภาษาสคริปต์ได้

เวอร์ชั่นสั้น...

มีเหตุผลใดที่จะชอบwhile (1)มากกว่าfor (;;)ถ้าคุณต้องการวงวนไม่สิ้นสุดเพื่อแยกออกจากกัน?

หมายเหตุ:หากยังไม่ชัดเจนจากคำถาม นี่เป็นการสนทนาทางวิชาการที่สนุกสนานระหว่างเพื่อนสองคน ฉันรู้ว่านี่ไม่ใช่แนวคิดที่สำคัญอย่างยิ่งที่โปรแกรมเมอร์ทุกคนควรทนทุกข์ทรมาน ขอบคุณสำหรับคำตอบที่ดีทั้งหมดที่ฉัน (และฉันแน่ใจว่าคนอื่น ๆ ) ได้เรียนรู้เล็ก ๆ น้อย ๆ จากการสนทนานี้

ปรับปรุง:เพื่อนร่วมงานดังกล่าวชั่งน้ำหนักด้วยคำตอบด้านล่าง

อ้างถึงที่นี่ในกรณีที่ถูกฝังอยู่

มันมาจากโปรแกรมเมอร์แอสเซมบลีของ AMD เขาระบุว่าโปรแกรมเมอร์ C (ผู้ประพันธ์) ไม่ทราบว่ารหัสของพวกเขาไม่มีประสิทธิภาพ เขากล่าวในวันนี้ว่าคอมไพเลอร์ gcc นั้นดีมากและทำให้คนอย่างเขาทำธุรกิจ เขากล่าวว่าเช่นและบอกฉันเกี่ยวกับVSwhile 1 for(;;)ฉันใช้มันตอนนี้นิสัย แต่ gcc และโดยเฉพาะล่ามจะดำเนินการเดียวกัน (ตัวประมวลผลกระโดด) สำหรับทั้งสองวันนี้เนื่องจากพวกเขาได้รับการปรับให้เหมาะสม


4
ฉันอยากรู้. เหตุใดจึงต้องวนซ้ำไม่สิ้นสุดในสคริปต์ Perl เห็นได้ชัดว่าคุณไม่ได้เขียนโปรแกรมไดรเวอร์หรือเป็นสิ่งที่ระบบ ... ไม่มีที่สิ้นสุดเป็นที่เงียบสงบยาว :-)
ลัค M

125
ลูปไม่สิ้นสุดอันไหนเร็วที่สุด? ฮ่า ๆ ... "คอมพิวเตอร์เครื่องใหม่ของฉันเป็นอย่างรวดเร็วมันวิ่งวง จำกัด ในเวลาเพียงหนึ่งชั่วโมง ..." ;-)
Arjan Einbu

8
นั่นคือศาสตราจารย์ด้านสังคมวิทยาที่บอกเขาว่า? ในยุคปัจจุบันรหัสที่คุณพิมพ์ไม่ใช่สิ่งที่คอมพิวเตอร์เห็น
ไบรอัน D ฟอย

5
ฉันคาดว่าจำนวนเวลาที่คุณต้องใช้ในการทดสอบนี้นานกว่าระยะเวลาที่อาจช่วยให้รอดได้โดยการรู้ว่าอันไหนเร็วกว่ากัน แม้ว่าคุณจะตัดจำหน่ายตลอดอายุการใช้งานของการเขียนโปรแกรม
Peter Recore

4
เหตุใดคอมไพเลอร์จะสร้างรหัสเพื่อทำการทดสอบที่รู้ว่าไม่มีผลข้างเคียงและคอมไพเลอร์รู้ผลของใครแล้ว? มันไม่สมเหตุสมผลเลย
David Schwartz

คำตอบ:


218

ใน Perl พวกเขาส่งผลให้ opcodes เดียวกัน:

$ perl -MO=Concise -e 'for(;;) { print "foo\n" }'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 -e:1) v ->3
9     <2> leaveloop vK/2 ->a
3        <{> enterloop(next->8 last->9 redo->4) v ->4
-        <@> lineseq vK ->9
4           <;> nextstate(main 1 -e:1) v ->5
7           <@> print vK ->8
5              <0> pushmark s ->6
6              <$> const[PV "foo\n"] s ->7
8           <0> unstack v ->4
-e syntax OK

$ perl -MO=Concise -e 'while(1) { print "foo\n" }'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 2 -e:1) v ->3
9     <2> leaveloop vK/2 ->a
3        <{> enterloop(next->8 last->9 redo->4) v ->4
-        <@> lineseq vK ->9
4           <;> nextstate(main 1 -e:1) v ->5
7           <@> print vK ->8
5              <0> pushmark s ->6
6              <$> const[PV "foo\n"] s ->7
8           <0> unstack v ->4
-e syntax OK

เช่นเดียวกันใน GCC:

#include <stdio.h>

void t_while() {
    while(1)
        printf("foo\n");
}

void t_for() {
    for(;;)
        printf("foo\n");
}

    .file   "test.c"
    .section    .rodata
.LC0:
    .string "foo"
    .text
.globl t_while
    .type   t_while, @function
t_while:
.LFB2:
    pushq   %rbp
.LCFI0:
    movq    %rsp, %rbp
.LCFI1:
.L2:
    movl    $.LC0, %edi
    call    puts
    jmp .L2
.LFE2:
    .size   t_while, .-t_while
.globl t_for
    .type   t_for, @function
t_for:
.LFB3:
    pushq   %rbp
.LCFI2:
    movq    %rsp, %rbp
.LCFI3:
.L5:
    movl    $.LC0, %edi
    call    puts
    jmp .L5
.LFE3:
    .size   t_for, .-t_for
    .section    .eh_frame,"a",@progbits
.Lframe1:
    .long   .LECIE1-.LSCIE1
.LSCIE1:
    .long   0x0
    .byte   0x1
    .string "zR"
    .uleb128 0x1
    .sleb128 -8
    .byte   0x10
    .uleb128 0x1
    .byte   0x3
    .byte   0xc
    .uleb128 0x7
    .uleb128 0x8
    .byte   0x90
    .uleb128 0x1
    .align 8
.LECIE1:
.LSFDE1:
    .long   .LEFDE1-.LASFDE1
.LASFDE1:
    .long   .LASFDE1-.Lframe1
    .long   .LFB2
    .long   .LFE2-.LFB2
    .uleb128 0x0
    .byte   0x4
    .long   .LCFI0-.LFB2
    .byte   0xe
    .uleb128 0x10
    .byte   0x86
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI1-.LCFI0
    .byte   0xd
    .uleb128 0x6
    .align 8
.LEFDE1:
.LSFDE3:
    .long   .LEFDE3-.LASFDE3
.LASFDE3:
    .long   .LASFDE3-.Lframe1
    .long   .LFB3
    .long   .LFE3-.LFB3
    .uleb128 0x0
    .byte   0x4
    .long   .LCFI2-.LFB3
    .byte   0xe
    .uleb128 0x10
    .byte   0x86
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI3-.LCFI2
    .byte   0xd
    .uleb128 0x6
    .align 8
.LEFDE3:
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

ดังนั้นฉันเดาว่าคำตอบคือพวกมันเหมือนกันในคอมไพเลอร์หลาย ๆ ตัว แน่นอนว่าสำหรับคอมไพเลอร์อื่น ๆ อาจไม่ได้เป็นอย่างนั้น แต่โอกาสที่รหัสภายในวงจะมีราคาแพงกว่าการวนซ้ำสองสามพันเท่าแล้วใครจะสนใจล่ะ


15
ลองกับ B :: Deparse, deparsing อนันต์สำหรับการวนกลับห่วงในขณะที่: P
Kent Fredric

27
"ในภาษา Perl พวกเขาให้ผลลัพธ์ opcodes เดียวกัน" ... ใช่ แต่เร็วกว่ากัน :-)
Tin Man

6
ฉันชอบที่ gcc ที่ถูกแทนที่จะทำให้ () สำหรับ printf () เนื่องจากมีเพียงอาร์กิวเมนต์เดียวเท่านั้นดังนั้นจึงไม่มีการจัดรูปแบบ - เร็วขึ้นและปลอดภัยยิ่งขึ้น! (gcc ยังตรวจสอบการจัดรูปแบบแท็กกับรายการอาร์กิวเมนต์ตัวแปร)
Lee D

@ The Tin Man: มันเทียบเท่ากันเพราะคอมพิวเตอร์ทำสิ่งที่เหมือนกัน: P
BlackBear

1
@snap มันไม่ถูก 'สมบูรณ์' มันแค่มุ่งเน้นไปที่ต้นทุนรันไทม์ ฉันไม่สามารถจินตนาการได้ว่าสถานการณ์แบบไหนที่จะส่งผลให้เวลาในการวิเคราะห์ลูปไม่สิ้นสุดเป็นปัจจัยสำคัญในการตัดสินใจว่าโปรแกรมของคุณจะทำงานเร็วแค่ไหน
bdonlan

55

ใช้ GCC พวกเขาทั้งคู่ดูเหมือนจะรวบรวมเป็นภาษาแอสเซมบลีเดียวกัน:

L2:
        jmp     L2

20
ใช้ GCC กับตัวเลือก -S (ไม่รวมลิงค์)
Martin Cote

54

ไม่มีเหตุผลมากนักที่จะชอบอีกคนหนึ่ง ฉันคิดว่าwhile(1)โดยเฉพาะอย่างยิ่งwhile(true)สามารถอ่านได้มากกว่าfor(;;)แต่นั่นเป็นเพียงการตั้งค่าของฉัน


94
#define EVER ;; สำหรับ (เคย) ฉันมักจะพบว่าชนิดของความสนุก
Tom

19
วิธี #define เคย (;;) ตลอดไป;
มาร์ติน Cote

16
ทั้งสองดูเหมือนจะอ่านได้ง่ายขึ้นบนพื้นผิว แต่ฉันไม่พยายามที่จะกำหนดคำหลักใหม่สำหรับโปรแกรมเมอร์บำรุงรักษาของฉัน (โดยปกติฉัน) เพื่อเกาหัวของเขา
Bill the Lizard

13
@ มาร์ตินที่ใช้งานไม่ได้เพราะ # define ไม่ได้ถูกแทนที่ด้วยโทเค็นและforeverเป็นโทเค็นของตัวเอง
Lily Chung

2
"ฉันพยายามที่จะไม่กำหนดคำหลักใหม่สำหรับการบำรุงรักษาของฉัน" - หากมีเพียงผู้คนจำนวนมากยอมรับทัศนคตินั้นฉันจะไม่กำหนดเสียน้ำทึ้งที่ไม่มีประโยชน์และมหัศจรรย์เหล่านี้ทุกครั้งที่ฉันหันไป!
tchrist

31

ไม่มีความแตกต่างตามมาตรฐาน 6.5.3 / 1 มี:

สำหรับงบ

for ( for-init-statement ; conditionopt ; expressionopt ) statement

เทียบเท่ากับ

{
  for-init-statement
  while ( condition ) {
    statement
    expression ;
  }
}

และ 6.5.3 / 2 มี:

สามารถละเว้นเงื่อนไขอย่างใดอย่างหนึ่งหรือทั้งสองอย่างและนิพจน์ได้ เงื่อนไขที่หายไปทำให้นัยในขณะที่ประโยคเทียบเท่ากับ (จริง)

ดังนั้นตามมาตรฐาน C ++ รหัส:

for (;;);

เหมือนกับ:

{
  while (true) {
    ;
    ;
  }
}

4
ซึ่งไม่เกี่ยวข้องกับรหัสหรือประสิทธิภาพที่สร้างขึ้นเลย มาตรฐานกำหนดฟังก์ชันการทำงานเท่านั้น แน่นอนประสิทธิภาพจะเหมือนกัน
Potatoswatter

1
ฉันไม่เชื่อว่ามันเป็นความจริงที่ความแตกต่างในการปฏิบัติงานละเมิดกฎ as-if หากเป็นเช่นนั้นคอมไพเลอร์จะไม่ได้รับอนุญาตให้เพิ่มความเร็วโค้ดของคุณภายใต้กฎ as-if ตัวอย่างเช่นโดยการสั่งซื้องบอิสระอีกครั้ง คอมไพเลอร์ในความเป็นจริงทำตรงนั้น แต่สำเนามาตรฐานของฉันอยู่ทางด้านบน
Steve Jessop

28

คอมไพเลอร์ Visual C ++ ที่ใช้ในการปล่อยคำเตือน

while (1) 

(นิพจน์คงที่) แต่ไม่ใช่สำหรับ

for (;;)

ฉันยังคงฝึกการเลือกfor (;;)เหตุผลต่อไป แต่ฉันไม่รู้ว่าผู้รวบรวมยังคงทำเช่นนั้นในวันนี้หรือไม่


เตือนอาจเป็นเพราะคุณใช้ในขณะที่ (1) แทนในขณะที่ (จริง)
jrharshath

16
ความจริงคือค่าคงที่ ในขณะที่ (จริง) คือการแสดงออกอย่างต่อเนื่อง สำหรับผู้ที่สนใจคำเตือน C4127 มีการจัดทำเอกสารไว้ที่นี่: msdn.microsoft.com/en-us/library/6t66728h(VS.80).aspx
sean e

ใช่คำเตือนยังคงปรากฏทั้ง 1 และจริง นั่นคือเหตุผลที่ฉันมักจะใช้สำหรับ (;;)
Elviss Strazdins

26

for(;;) เป็นหนึ่งในตัวละครที่พิมพ์น้อยถ้าคุณต้องการไปในทิศทางนั้นเพื่อปรับสิ่งต่าง ๆ ให้เหมาะสม


21
เป็นการดีที่จะรู้ว่าสำหรับการเล่นกอล์ฟ มิฉะนั้นเป็นเหตุผลที่ไม่ดีในการเลือกไวยากรณ์
Adam Bellaire

@ AdamBellaire Terseness มักจะเพิ่มความสามารถในการอ่านได้เหนือขีด จำกัด ของทักษะบางอย่าง
Vector Gorgoth

20

Turbo C ที่มีคอมไพเลอร์เก่านี้ผลในรหัสได้เร็วขึ้นแล้วfor(;;)while(1)

วันนี้ gcc, Visual C (ฉันคิดว่าเกือบทั้งหมด) คอมไพเลอร์ปรับให้เหมาะสมและ CPU ที่มี 4.7 MHz ไม่ค่อยได้ใช้

ในสมัยนั้น a for( i=10; i; i-- )เร็วกว่าfor( i=1; i <=10; i++ )เนื่องจากการเปรียบเทียบiเป็น 0 ผลลัพธ์ในการกระโดดตามเงื่อนไขของ CPU-Zero-Flag และ Zero-Flag ได้รับการแก้ไขด้วยการลดทอนครั้งล่าสุด( i-- )ไม่จำเป็นต้องมีการใช้งาน cmp เพิ่มเติม

    call    __printf_chk
    decl    %ebx          %ebx=iterator i 
    jnz     .L2
    movl    -4(%ebp), %ebx
    leave

และที่นี่ด้วยfor(i=1; i<=10; i++)cmpl พิเศษ:

    call    __printf_chk
    incl    %ebx
    cmpl    $11, %ebx
    jne     .L2
    movl    -4(%ebp), %ebx
    leave

13

สำหรับทุกคนที่โต้เถียงคุณไม่ควรใช้ indefinte ในขณะที่ลูปและแนะนำสิ่งที่บ้าคลั่งเช่นใช้ open goto (จริงจังจริงจัง)

while (1) {
     last if( condition1 );
     code();
     more_code(); 
     last if( condition2 ); 
     even_more_code(); 
}

ไม่สามารถแสดงได้อย่างมีประสิทธิภาพด้วยวิธีอื่น ไม่ได้โดยไม่ต้องสร้างตัวแปรทางออกและทำเวทมนต์ดำเพื่อทำให้ข้อมูลตรงกัน

หากคุณมีใจชอบไวยากรณ์ที่เพิ่มมากขึ้นให้ใช้สิ่งที่มีสติซึ่ง จำกัด ขอบเขต

flow: { 

   if ( condition ){ 
      redo flow;
   }
   if ( othercondition ){ 
       redo flow;
   }
   if ( earlyexit ){ 
       last flow;
   }
   something(); # doesn't execute when earlyexit is true 
}

ในที่สุดความเร็วก็ไม่สำคัญเท่าไหร่

การกังวลเกี่ยวกับความเร็วที่มีประสิทธิภาพของการสร้างลูปที่แตกต่างกันอย่างชาญฉลาดนั้นเป็นการเสียเวลามาก การเพิ่มประสิทธิภาพก่อนวัยอันควรผ่านและผ่าน ฉันไม่สามารถนึกถึงสถานการณ์ใด ๆ ที่ฉันเคยเห็นที่รหัสการทำโปรไฟล์พบปัญหาคอขวดในตัวเลือกการวนลูปของฉัน

โดยทั่วไปแล้วมันเป็นวิธีการของห่วงและสิ่งที่ห่วง

คุณควร "ปรับ" ให้เหมาะสมสำหรับการอ่านและความรัดกุมและเขียนสิ่งที่ดีที่สุดในการอธิบายปัญหาไปยังผู้อมยิ้มรายถัดไปที่พบรหัสของคุณ

หากคุณใช้ "โกโตะ LABEL" เคล็ดลับใครบางคนที่กล่าวถึงและฉันต้องใช้รหัสของคุณได้เตรียมที่จะหลับนอนกับตาเปิดหนึ่งโดยเฉพาะอย่างยิ่งถ้าคุณทำมันมากกว่าหนึ่งครั้งเพราะการจัดเรียงของสิ่งที่สร้างความสยองรหัสปาเก็ตตี้

เพียงเพราะคุณสามารถสร้างรหัสสปาเก็ตตี้ไม่ได้หมายความว่าคุณควร


9

จาก Stroustrup, TC ++ PL (รุ่นที่ 3), §6.1.1:

สัญกรณ์อยากรู้อยากเห็นfor (;;)เป็นวิธีมาตรฐานในการระบุวงไม่สิ้นสุด คุณสามารถออกเสียงว่า "ถาวร" [... ] while (true)เป็นทางเลือก

for (;;)ฉันชอบ


9

หากคอมไพเลอร์ไม่ทำการเพิ่มประสิทธิภาพใด ๆfor(;;)ก็จะเร็วกว่าwhile(true)เสมอ นี่เป็นเพราะ while-statement ประเมินเงื่อนไขทุกครั้ง แต่ for-statement เป็นการกระโดดแบบไม่มีเงื่อนไข แต่ถ้าคอมไพเลอร์ปรับการควบคุมการไหลให้เหมาะสมมันอาจสร้าง opcode บางตัว คุณสามารถอ่านรหัสถอดแยกชิ้นส่วนได้ง่ายมาก

ป.ล. คุณสามารถเขียนวนรอบไม่สิ้นสุดเช่นนี้:

#define EVER ;;
  //...
  for (EVER) {
    //...
  }

ในยุคปัจจุบันและอายุไม่ควรถูกแทนที่ด้วย EVS (วัยรุ่นพูด)! อย่างจริงจังแม้ว่าฉันเพียงแค่ใช้สำหรับ (;;) {} ฉันอ่านออนไลน์เมื่อนานมาแล้วเกี่ยวกับความแตกต่างระหว่างคนทั้งสอง (เมื่อฉันยังเด็กและไม่รู้จริง ๆ ว่าพวกเขาเหมือนกัน) และเพิ่งติดอยู่กับสิ่งที่ฉันอ่าน
Bja

8

ฉันเคยได้ยินเกี่ยวกับเรื่องนี้ครั้งเดียว

มันมาจากโปรแกรมเมอร์แอสเซมบลีของ AMD เขากล่าวว่าโปรแกรมเมอร์ C (คน) ไม่ทราบว่ารหัสของพวกเขาไม่มีประสิทธิภาพ เขากล่าวในวันนี้ว่าคอมไพเลอร์ gcc นั้นดีมากและทำให้คนอย่างเขาทำธุรกิจ เขากล่าวว่าเช่นและบอกฉันเกี่ยวกับVSwhile 1 for(;;)ฉันใช้มันตอนนี้นิสัย แต่ gcc และโดยเฉพาะล่ามจะดำเนินการเดียวกัน (ตัวประมวลผลกระโดด) สำหรับทั้งสองวันนี้เนื่องจากพวกเขาได้รับการปรับให้เหมาะสม


5

ในโครงสร้างที่ได้รับการปรับปรุงของภาษาที่คอมไพล์แล้วควรไม่มีความแตกต่างที่เห็นได้ระหว่างสองภาษา ไม่ควรทำการเปรียบเทียบใด ๆ ที่รันไทม์พวกเขาจะรันโค้ดลูปจนกว่าคุณจะออกจากลูปด้วยตนเอง (เช่นด้วย a break)


3

ฉันประหลาดใจที่ไม่มีใครทดสอบอย่างถูกต้องfor (;;)กับwhile (1)Perl!

เนื่องจากภาษา Perl แปลภาษาเวลาในการเรียกใช้สคริปต์ Perl ไม่เพียง แต่ประกอบด้วยช่วงการดำเนินการเท่านั้น (ซึ่งในกรณีนี้คือเหมือนกัน) แต่ยังเป็นช่วงการตีความก่อนดำเนินการด้วย ขั้นตอนเหล่านี้ทั้งสองจะต้องนำมาพิจารณาเมื่อทำการเปรียบเทียบความเร็ว

โชคดีที่ Perl มีโมดูลเกณฑ์มาตรฐานที่สะดวกซึ่งเราสามารถใช้เพื่อสร้างเกณฑ์มาตรฐานเช่น:

#!/usr/bin/perl -w

use Benchmark qw( cmpthese );

sub t_for   { eval 'die; for (;;) { }'; }
sub t_for2  { eval 'die; for (;;)  { }'; }
sub t_while { eval 'die; while (1) { }'; }

cmpthese(-60, { for => \&t_for, for2 => \&t_for2, while => \&t_while });

โปรดทราบว่าฉันกำลังทดสอบอนันต์วนลูปสองเวอร์ชัน: อันหนึ่งสั้นกว่าขณะลูปและอีกอันหนึ่งซึ่งมีพื้นที่พิเศษเพื่อให้มีความยาวเท่ากับลูปในขณะที่

บน Ubuntu 11.04 x86_64 ด้วย perl 5.10.1 ฉันได้ผลลัพธ์ดังนี้:

          อัตราสำหรับ 2 ในขณะที่
สำหรับ 100588 / s - -0% -2%
for2 100937 / s 0% - -1%
ในขณะที่ 102147 / s 2% 1% -

ขณะที่ลูปเป็นผู้ชนะอย่างชัดเจนในแพลตฟอร์มนี้

ใน FreeBSD 8.2 x86_64 ด้วย perl 5.14.1:

         อัตราสำหรับ 2 ในขณะที่
สำหรับ 53453 / s - -0% -2%
for2 53552 / s 0% - -2%
ในขณะที่ 54564 / s 2% 2% -

ในขณะที่วงเป็นผู้ชนะที่นี่ด้วย

บน FreeBSD 8.2 i386 ด้วย perl 5.14.1:

         ให้คะแนนในขณะที่ for2
ในขณะที่ 24311 / s - -1% -1%
สำหรับ 24481 / s 1% - -1%
for2 24637 / s 1% 1% -

น่าประหลาดใจที่วงที่มีพื้นที่ว่างเพิ่มเป็นตัวเลือกที่เร็วที่สุดที่นี่!

ข้อสรุปของฉันคือขณะที่ลูปควรใช้บนแพลตฟอร์ม x86_64 หากโปรแกรมเมอร์กำลังปรับให้เหมาะสมสำหรับความเร็ว เห็นได้ชัดว่าควรใช้ a for loop เมื่อปรับพื้นที่ให้เหมาะสม ผลลัพธ์ของฉันยังสรุปไม่ได้เกี่ยวกับแพลตฟอร์มอื่น


9
ข้อสรุปผิดอย่างโจ๋งครึ่ม Benchmarkมีข้อ จำกัด และไม่สามารถใช้เพื่อแยกความแตกต่างอย่างรวดเร็วจากช้าหากผลลัพธ์อยู่ภายใน 7% ของกันและกัน ยิ่งกว่านั้นคุณยังไม่ได้ทดสอบความแตกต่างระหว่างforและกับwhileลูปเพราะแต่ละย่อยจะdieถึงลูปก่อน และเมื่อใดที่จำนวนของช่องว่างมีความสำคัญต่อล่าม Perl? ขออภัยการวิเคราะห์มีข้อบกพร่องอย่างมาก
Zaid

2
@ Zaid ขอบคุณสำหรับความคิดเห็นของคุณ! คุณจะโพสต์คำตอบของคุณเองเพื่อให้ทุกคนสามารถเรียนรู้จากสิ่งนั้นได้หรือไม่? :) dieมีในรหัสของฉันเพราะความตั้งใจของฉันคือการทดสอบความแตกต่างเวลารวบรวมเท่านั้น ตามที่คนอื่น ๆ ได้ชี้ให้เห็นแล้วว่ารหัสไบต์ที่ได้นั้นเหมือนกันดังนั้นจึงไม่มีประเด็นในการทดสอบว่า น่าแปลกที่ปริมาณพื้นที่สีขาวดูเหมือนจะสร้างความแตกต่างเล็กน้อยในกรณีนี้ในสภาพแวดล้อมการทดสอบของฉัน มันอาจจะมีสิ่งที่จะทำอย่างไรกับตัวละครสิ้นสุดการชิดในหน่วยความจำหรือสิ่งที่คล้ายกัน ...
สแน็ป

4
ฉันไม่จำเป็นต้องโพสต์คำตอบเพราะสิ่งที่ฉันจะพูดได้ถูกกล่าวถึงโดย bdonlan และแม้ว่าคุณจะเปรียบเทียบเวลารวบรวมตัวเลขที่Benchmarkไม่สามารถสรุปได้ อย่าไว้ใจความแตกต่าง 1% เลย!
Zaid

มีเพียง 60 รอบเท่านั้น ทำการทดสอบเป็นเวลา 5 นาทีเพื่อให้ได้เวลาสัมพัทธ์ที่แม่นยำยิ่งขึ้น
Mooing Duck

-60รันการทดสอบเป็นเวลา 60 วินาที
snap

2

ในทางทฤษฎีคอมไพเลอร์ที่ไร้เดียงสาอย่างสมบูรณ์สามารถเก็บตัวอักษร '1' ในไบนารี่ (พื้นที่ว่างเปล่า) และตรวจสอบเพื่อดูว่า 1 == 0 ทุกการวนซ้ำ (เสียเวลาและพื้นที่ว่างมากขึ้น)

ในความเป็นจริงอย่างไรก็ตามถึงแม้จะมีการเพิ่มประสิทธิภาพ "ไม่" คอมไพเลอร์จะยังคงลดลงทั้งสองเหมือนกัน พวกเขายังอาจส่งคำเตือนเพราะอาจบ่งบอกถึงข้อผิดพลาดเชิงตรรกะ ตัวอย่างเช่นการโต้แย้งของwhileสามารถกำหนดที่อื่นและคุณไม่ได้ตระหนักว่ามันคงที่


2

ฉันประหลาดใจที่ไม่มีใครเสนอรูปแบบที่ตรงมากขึ้นซึ่งสอดคล้องกับชุดประกอบที่ต้องการ:

forever:
     do stuff;
     goto forever;

ขนาดที่ไม่ได้ลงทะเบียนด้วยรหัสเครื่องเดียวกับในขณะที่ 1 หรือสำหรับ (;;) เป็น c?
Copas

1
ข้อบกพร่องอีกข้อหนึ่งของวิธีการนี้: มันเป็นการละเมิดการห่อหุ้มโดยไม่ล้อมรอบวงในบล็อก - ดังนั้นตัวแปรใด ๆ ที่ประกาศในลูปจะพร้อมใช้งานนอกลูป (แน่นอนคุณทำได้{ forever: do stuff; goto forever; })
Roy Tinker

2

while(1)เป็นสำนวนfor(;;)ที่นักแปลส่วนใหญ่ยอมรับ

ฉันดีใจที่เห็นว่า Perl ตระหนักuntil(0)เช่นกัน


ในสถานการณ์ใดจะถึง (0) จะมีประโยชน์?
Copas

3
จนกระทั่ง () เป็นสิ่งที่ตรงกันข้ามกับขณะที่ () เช่นเดียวกับ () เป็นสิ่งที่ตรงกันข้ามกับถ้า () ตามที่แนะนำในทุกที่ในหัวข้อนี้ใคร ๆ ก็เขียนว่า: ทำ {some ... } while ในขณะที่ (! condition) ทางเลือกอื่นอาจจะเป็นไปจนถึง (condition) {something}
JMD

2

เพื่อสรุปการโต้วาทีfor (;;)vs while (1)เห็นได้ชัดว่าอดีตนั้นเร็วขึ้นในวันที่คอมไพเลอร์เก่าที่ไม่ได้เพิ่มประสิทธิภาพนั่นคือเหตุผลที่คุณมักจะเห็นมันในฐานรหัสเก่าเช่นความเห็นรหัส Lions Unix ซอร์สโค้ดอย่างไรก็ตามในยุคของการเพิ่มประสิทธิภาพ badass การรวบรวมผลกำไรเหล่านั้นได้รับการปรับให้เหมาะกับการมีเพศสัมพันธ์กับความจริงที่ว่าหลังจะเข้าใจได้ง่ายกว่าในอดีตฉันเชื่อว่ามันจะเป็นที่นิยมมากกว่า


2

เพิ่งเจอหัวข้อนี้ (แม้ว่าจะค่อนข้างช้าไม่กี่ปี)

ฉันคิดว่าฉันพบเหตุผลที่แท้จริงว่าทำไม "for (;;)" ดีกว่า "ในขณะที่ (1)"

ตามที่ "มาตรฐานการเข้ารหัส barr 2018"

Kernighan & Ritchie long ago recommended for (;;) , which has the additional benefit
of insuring against the visually-confusing defect of a while (l); referencing a variable l’.

โดยทั่วไปนี่ไม่ใช่ปัญหาความเร็ว แต่เป็นปัญหาการอ่านได้ง่าย ขึ้นอยู่กับแบบอักษร / พิมพ์ของรหัสหมายเลขหนึ่ง (1) ในขณะที่อาจดูเหมือนตัวอักษรตัวพิมพ์เล็ก l

เช่น 1 vs l (ในแบบอักษรบางแบบจะมีลักษณะเหมือนกัน)

ดังนั้นในขณะที่ (1) อาจดูเหมือนบางอย่างในขณะที่วงขึ้นอยู่กับตัวอักษรตัวแปร L

ในขณะที่ (จริง) อาจทำงานได้ แต่ใน C เก่าและกรณี C ฝังตัวจริง / เท็จยังไม่ได้กำหนดเว้นแต่ stdbool.h รวมอยู่


2
ฉันจะบอกว่าปัญหาในรหัสของคุณจะเป็นว่าคุณมีชื่อตัวแปรlไม่ว่า1และlสามารถมีลักษณะคล้ายกัน
mjuopperi

เห็นด้วยฉันรู้ว่ามาตรฐานการเข้ารหัส Barr ยังบอกที่อื่นว่าตัวแปรต้องมีอย่างน้อย 3 ตัวอักษรแม้กระทั่งในลูป เช่นไม่มี i ++ เป็นต้นใน for for loop ฉันมักจะคิดว่าอาจจะค่อนข้างมาก ในขณะที่พิมพ์ฉันก็สังเกตเห็นว่ามันไม่ใช่แค่ตัวอักษร L ที่มีลักษณะเป็น 1 ตัวอักษร i ซึ่งใช้กันทั่วไปเป็นตัวแปรอาจทำให้เกิดปัญหาได้เช่นกัน
Nick Law

-3

ฉันคิดว่าทั้งสองอย่างนั้นเหมือนกันในแง่ของประสิทธิภาพ แต่ฉันต้องการในขณะที่ (1) สำหรับการอ่าน แต่ฉันถามว่าทำไมคุณต้องวนซ้ำไม่สิ้นสุด


-14

พวกเขาก็เหมือน ๆ กัน. มีคำถามสำคัญมากมายที่ต้องไตร่ตรอง


จุดของฉันซึ่งส่อให้เห็น แต่ไม่ได้ทำอย่างชัดเจนข้างต้นคือคอมไพเลอร์ที่ดีจะสร้างรหัสเดียวกันแน่นอนสำหรับทั้งสองรูปแบบวง จุดที่ใหญ่กว่าคือโครงสร้างลูปเป็นส่วนย่อยของรันไทม์ของอัลกอริทึมใด ๆ และคุณต้องแน่ใจก่อนว่าคุณได้ปรับอัลกอริทึมให้เหมาะสมและทุกอย่างที่เกี่ยวข้องกับมัน การเพิ่มประสิทธิภาพการสร้างลูปของคุณควรอยู่ที่ด้านล่างสุดของรายการลำดับความสำคัญของคุณ


22
ไม่มีลิงก์หรือคำอธิบาย ไม่ช่วยเหลือเป็นส่วนตัวและวางตัวเล็กน้อย
cdmckay

1
ดีไม่มีข้อพิสูจน์ แต่เขาพูดถูก พวกเขาทั้งสองเรียก Opcode เพื่อกระโดดเมื่อผิด (ซึ่งจะทำให้มันเป็นเช่นเดียวกับข้ามไป แต่ไม่มีใครชอบ gotos)
แมทธิว Whited

3
ฉันไม่รู้ว่ามีคำถามสำคัญที่ควรถามเท่านั้นความผิดพลาดของฉันคือคำถามแรก
Copas

3
ใช่ฉันยอมรับว่ากำลังวางตัว แต่อย่างจริงจังแม้ว่าจะไม่มีข้อพิสูจน์ใด ๆ ก็เป็นที่ชัดเจนว่าพวกเขากำลังจะอยู่ใน ballpark เดียวกันตามเข็มนาฬิกา; หากคำถามเกี่ยวกับรูปแบบจะมีบางสิ่งที่จะโต้แย้ง ฉันพยายามทำให้ประเด็นที่รายการสิ่งที่ต้องกังวลเกี่ยวกับเรื่องนี้ควรจะอยู่ด้านล่างของรายการ
Mark Ransom

8
ฉันไม่ได้พยายามที่จะกระตุก ฉันพยายามทำประเด็น เมื่อฉันโพสต์มันฉันกำลังพยายามหาอารมณ์ขันที่มืดมนและมันชัดเจนว่าฉันล้มเหลว เพราะฉันขอโทษ
Mark Ransom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.