Cái nào nhanh hơn: while (1) hay while (2)?


587

Đây là một câu hỏi phỏng vấn được hỏi bởi một người quản lý cao cấp.

Cái nào nhanh hơn?

while(1) {
    // Some code
}

hoặc là

while(2) {
    //Some code
}

Tôi đã nói rằng cả hai đều có cùng tốc độ thực hiện, vì biểu thức bên trong whilecuối cùng sẽ đánh giá đến truehoặc false. Trong trường hợp này, cả hai đánh giá truevà không có hướng dẫn điều kiện bổ sung bên trong whileđiều kiện. Vì vậy, cả hai sẽ có cùng tốc độ thực hiện và tôi thích trong khi (1).

Nhưng người phỏng vấn tự tin nói: "Hãy kiểm tra những điều cơ bản của bạn. while(1)Nhanh hơn while(2)." (Anh ấy đã không kiểm tra sự tự tin của tôi)

Điều này có đúng không?

Xem thêm: "for (;;)" có nhanh hơn "while (TRUE)" không? Nếu không, tại sao mọi người sử dụng nó?


202
Một trình biên dịch nửa phong nha sẽ tối ưu hóa cả hai hình thức thành không có gì.

64
Trong bản dựng được tối ưu hóa mọi lúc (n), n! = 0 hoặc for (;;) sẽ được dịch thành vòng lặp vô tận hội với nhãn ở đầu và goto ở cuối. Chính xác cùng một mã, hiệu suất như nhau.
Alex F

60
Không có gì đáng ngạc nhiên, một tối ưu hóa chứng khoán mang lại 0x100000f90: jmp 0x100000f90(địa chỉ khác nhau, rõ ràng) cho cả hai đoạn. Người phỏng vấn có thể đã tham gia một bài kiểm tra đăng ký so với bước nhảy đơn giản. Cả câu hỏi, và giả định của họ, là khập khiễng.
WhozCraig

50
Câu hỏi này của người phỏng vấn nằm dưới sự bảo trợ tương tự như Dilbert.com/strips/comic/1995-11-17 - bạn sẽ gặp một người thực sự tin những gì họ đang nói bất kể chỉ số ngu ngốc trong tuyên bố của họ. Đơn giản chỉ cần chọn một trong các cách sau: hít thở sâu, chửi thề, cười, khóc, một số kết hợp của những điều trên :)
GMasucci

3
@Mike W: người ta có thể tự hỏi trình biên dịch nên làm gì: dịch sang câu lệnh Halt hoặc xem xét rằng vòng lặp thoát sau thời gian vô hạn và tối ưu hóa độ trễ vô hạn?
Yves Daoust

Câu trả lời:


681

Cả hai vòng lặp là vô hạn, nhưng chúng ta có thể thấy cái nào cần nhiều hướng dẫn / tài nguyên hơn cho mỗi lần lặp.

Sử dụng gcc, tôi đã biên dịch hai chương trình sau để lắp ráp ở các mức độ tối ưu hóa khác nhau:

int main(void) {
    while(1) {}
    return 0;
}


int main(void) {
    while(2) {}
    return 0;
}

Ngay cả khi không có tối ưu hóa ( -O0), lắp ráp được tạo là giống hệt nhau cho cả hai chương trình . Do đó, không có sự khác biệt về tốc độ giữa hai vòng.

Để tham khảo, đây là hội đồng được tạo (sử dụng gcc main.c -S -masm=intelvới cờ tối ưu hóa):

Với -O0:

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    push    rbp
    .seh_pushreg    rbp
    mov rbp, rsp
    .seh_setframe   rbp, 0
    sub rsp, 32
    .seh_stackalloc 32
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Với -O1:

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Với -O2-O3(cùng đầu ra):

    .file   "main.c"
    .intel_syntax noprefix
    .def    __main; .scl    2;  .type   32; .endef
    .section    .text.startup,"x"
    .p2align 4,,15
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    __main
.L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Trong thực tế, lắp ráp được tạo cho vòng lặp là giống hệt nhau cho mọi cấp độ tối ưu hóa:

 .L2:
    jmp .L2
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Các bit quan trọng là:

.L2:
    jmp .L2

Tôi không thể đọc lắp ráp rất tốt, nhưng đây rõ ràng là một vòng lặp vô điều kiện. Các jmphướng dẫn cách vô điều kiện reset chương trình trở lại .L2nhãn mà không cần so sánh một giá trị so với sự thật, và tất nhiên ngay lập tức làm như vậy một lần nữa cho đến khi chương trình được bằng cách nào đó đã kết thúc. Điều này tương ứng trực tiếp với mã C / C ++:

L2:
    goto L2;

Biên tập:

Thật thú vị, ngay cả khi không có tối ưu hóa , tất cả các vòng lặp sau đây đều tạo ra cùng một đầu ra (vô điều kiện jmp) trong lắp ráp:

while(42) {}

while(1==1) {}

while(2==2) {}

while(4<7) {}

while(3==3 && 4==4) {}

while(8-9 < 0) {}

while(4.3 * 3e4 >= 2 << 6) {}

while(-0.1 + 02) {}

Và thậm chí làm tôi ngạc nhiên:

#include<math.h>

while(sqrt(7)) {}

while(hypot(3,4)) {}

Mọi thứ trở nên thú vị hơn với các hàm do người dùng định nghĩa:

int x(void) {
    return 1;
}

while(x()) {}


#include<math.h>

double x(void) {
    return sqrt(7);
}

while(x()) {}

Tại -O0, hai ví dụ này thực sự gọi xvà thực hiện so sánh cho mỗi lần lặp.

Ví dụ đầu tiên (trả về 1):

.L4:
    call    x
    testl   %eax, %eax
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Ví dụ thứ hai (trở về sqrt(7)):

.L4:
    call    x
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jp  .L4
    xorpd   %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    jne .L4
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (tdm64-2) 4.8.1"

Tuy nhiên, tại -O1và trên, cả hai đều tạo ra một hội đồng giống như các ví dụ trước (một điều kiện vô điều kiện jmptrở lại nhãn trước).

TL; DR

Theo GCC, các vòng lặp khác nhau được biên dịch để lắp ráp giống hệt nhau. Trình biên dịch đánh giá các giá trị không đổi và không bận tâm thực hiện bất kỳ so sánh thực tế nào.

Đạo đức của câu chuyện là:

  • Tồn tại một lớp dịch giữa mã nguồn C ++ và các hướng dẫn CPU và lớp này có ý nghĩa quan trọng đối với hiệu năng.
  • Do đó, hiệu suất không thể được đánh giá bằng cách chỉ nhìn vào mã nguồn.
  • Trình biên dịch phải đủ thông minh để tối ưu hóa các trường hợp tầm thường như vậy. Các lập trình viên không nên lãng phí thời gian suy nghĩ về họ trong phần lớn các trường hợp.

196
Có lẽ người phỏng vấn không sử dụng gcc
MM

106
@Matt McNabb Đó là một điểm tốt, nhưng nếu người phỏng vấn dựa vào sự tối ưu hóa cụ thể của trình biên dịch, thì họ cần phải rất rõ ràng về câu hỏi đó và họ cần chấp nhận câu trả lời "không có gì khác biệt" một số trình biên dịch (hầu hết?).
Jonathan Hartley

109
Để xóa bỏ mọi nghi ngờ, tôi đã thử nghiệm điều này trong clang 3.4.2 và cả hai vòng lặp đều tạo ra cùng một tổ hợp ở mọi -Ocấp độ.
Martin Tournoij

16
Tôi không thấy điều này đáng ngạc nhiên vì tất cả mọi thứ bạn đã đặt trong phần có điều kiện của các vòng lặp là hằng số thời gian biên dịch. Như vậy, tôi nghi ngờ một trình biên dịch sẽ thấy chúng các vòng lặp sẽ luôn đúng hoặc sai và chỉ đơn giản là jmpquay trở lại từ đầu hoặc loại bỏ hoàn toàn vòng lặp.
sherrellbc

10
@hippietrail Tôi không thấy cách nội dung (hoặc thiếu ở đây) của vòng lặp có thể ảnh hưởng đến các tối ưu hóa này (ngoại trừ khả năng của bất kỳ breakcâu lệnh nào ), nhưng tôi chỉ kiểm tra nó bằng mọi cách và không, ngay cả với mã bên trong vòng lặp nhảy tuyệt đối và vô điều kiện cho cả while(1)while(2). Hãy tự mình kiểm tra những người khác nếu bạn thực sự quan tâm.
Tiếp

282

Vâng, while(1)nhanh hơn nhiều so với while(2), cho một con người để đọc! Nếu tôi nhìn thấy while(1)trong một cơ sở mã lạ, tôi biết ngay tác giả dự định và nhãn cầu của tôi có thể tiếp tục dòng tiếp theo.

Nếu tôi thấy while(2), có lẽ tôi sẽ dừng các bài hát của mình và cố gắng tìm hiểu tại sao tác giả không viết while(1). Có phải ngón tay của tác giả trượt trên bàn phím? Các nhà bảo trì của cơ sở mã này sử dụng while(n)như một cơ chế bình luận tối nghĩa để làm cho các vòng lặp trông khác nhau? Đây có phải là một cách giải quyết thô thiển cho một cảnh báo giả trong một số công cụ phân tích tĩnh bị hỏng không? Hay đây là một đầu mối mà tôi đang đọc mã được tạo ra? Đây có phải là một lỗi xuất phát từ việc tìm và thay thế tất cả, hoặc hợp nhất xấu, hoặc tia vũ trụ không? Có lẽ dòng mã này được cho là sẽ làm một cái gì đó khác biệt đáng kể. Có lẽ nó được cho là để đọc while(w)hoặc while(x2). Tôi tốt hơn nên tìm tác giả trong lịch sử của tập tin và gửi cho họ email "WTF" ... và bây giờ tôi đã phá vỡ bối cảnh tinh thần của mình.while(2)while(1) sẽ mất một phần của giây!

Tôi đang phóng đại, nhưng chỉ một chút thôi. Mã dễ đọc là thực sự quan trọng. Và đó là điều đáng nói trong một cuộc phỏng vấn!


Suy nghĩ của tôi chính xác, và chính xác tại sao trong khi (1) lại nhanh hơn lol Mặc dù tôi nghĩ đó đơn giản là trường hợp cũ của một người quản lý đang cố gắng thuyết phục bản thân rằng anh ta biết về tiền mã hóa khi anh ta không biết, tất cả mọi người đều muốn, jedi.
ekerner

8
Tuyệt đối, đây không phải là cường điệu chút nào. Chắc chắn svn-annotate hoặc git blame(hoặc bất cứ điều gì) sẽ được sử dụng ở đây, và nói chung phải mất vài phút để tải một lịch sử đổ lỗi cho tập tin. Sau đó, cuối cùng tôi quyết định "ah tôi hiểu, tác giả đã viết dòng này khi mới ra khỏi trường trung học", chỉ mất 10 phút ...
v.oddou

11
Bỏ phiếu xuống vì tôi chán các quy ước. Nhà phát triển có cơ hội chơi chữ này để viết một số anh ta thích, sau đó ai đó nhàm chán đến và nói xấu về lý do tại sao nó không 1.
Utkan Gezer

1
Downvote do hùng biện. Đọc while (1) chính xác là cùng tốc độ với while (2).
hdante

4
Tôi đã trải qua quá trình tinh thần chính xác như được mô tả trong câu trả lời này một phút trước khi tôi thấy while(2)trong đoạn mã (xem xét "Các nhà duy trì của cơ sở mã hóa này có sử dụng trong khi (n) như một cơ chế nhận xét tối nghĩa để làm cho các vòng lặp trông khác nhau không?" ). Vì vậy, không, bạn không phóng đại!
Hisham HM

151

Các câu trả lời hiện có hiển thị mã được tạo bởi một trình biên dịch cụ thể cho một mục tiêu cụ thể với một bộ tùy chọn cụ thể không trả lời đầy đủ câu hỏi - trừ khi câu hỏi được hỏi trong ngữ cảnh cụ thể đó ("Sử dụng gcc 4.7.2 nhanh hơn cho x86_64 với các tùy chọn mặc định? ", ví dụ).

Theo như định nghĩa ngôn ngữ, trong máy trừu tượng sẽ while (1) đánh giá hằng số nguyên 1while (2)đánh giá hằng số nguyên 2; trong cả hai trường hợp, kết quả được so sánh bằng nhau bằng không. Tiêu chuẩn ngôn ngữ hoàn toàn không nói gì về hiệu suất tương đối của hai cấu trúc.

Tôi có thể tưởng tượng rằng một trình biên dịch cực kỳ ngây thơ có thể tạo mã máy khác nhau cho hai biểu mẫu, ít nhất là khi được biên dịch mà không yêu cầu tối ưu hóa.

Mặt khác, trình biên dịch C hoàn toàn phải đánh giá một số biểu thức không đổi tại thời gian biên dịch, khi chúng xuất hiện trong bối cảnh yêu cầu biểu thức không đổi. Ví dụ: cái này:

int n = 4;
switch (n) {
    case 2+2: break;
    case 4:   break;
}

yêu cầu chẩn đoán; một trình biên dịch lười biếng không có tùy chọn trì hoãn việc đánh giá 2+2cho đến khi thời gian thực hiện. Vì trình biên dịch phải có khả năng đánh giá các biểu thức không đổi trong thời gian biên dịch, không có lý do chính đáng nào để nó không tận dụng khả năng đó ngay cả khi không cần thiết.

Tiêu chuẩn C ( N1570 6.8.5p4) nói rằng

Một câu lệnh lặp làm cho một câu lệnh được gọi là thân vòng lặp được thực thi lặp đi lặp lại cho đến khi biểu thức điều khiển so sánh bằng 0.

Vì vậy, các biểu thức hằng có liên quan là 1 == 02 == 0, cả hai đều đánh giá giá inttrị 0. (Những so sánh này được ẩn trong ngữ nghĩa của whilevòng lặp; chúng không tồn tại như các biểu thức C thực tế.)

Một trình biên dịch ngây thơ có thể tạo mã khác nhau cho hai cấu trúc. Ví dụ, lần đầu tiên, nó có thể tạo ra một vòng lặp vô hạn vô điều kiện (coi 1như một trường hợp đặc biệt) và trong lần thứ hai, nó có thể tạo ra một so sánh thời gian chạy rõ ràng tương đương với 2 != 0. Nhưng tôi chưa bao giờ gặp phải một trình biên dịch C thực sự sẽ hoạt động theo cách đó và tôi thực sự nghi ngờ rằng trình biên dịch đó tồn tại.

Hầu hết các trình biên dịch (tôi muốn nói rằng tất cả các trình biên dịch chất lượng sản xuất) đều có các tùy chọn để yêu cầu tối ưu hóa bổ sung. Trong một tùy chọn như vậy, ít có khả năng bất kỳ trình biên dịch nào sẽ tạo mã khác nhau cho hai biểu mẫu.

Nếu trình biên dịch của bạn tạo mã khác nhau cho hai cấu trúc, trước tiên hãy kiểm tra xem các chuỗi mã khác nhau có thực sự có hiệu suất khác nhau không. Nếu có, hãy thử biên dịch lại với tùy chọn tối ưu hóa (nếu có). Nếu chúng vẫn khác nhau, hãy gửi báo cáo lỗi cho nhà cung cấp trình biên dịch. Đó không phải là (nhất thiết) một lỗi theo nghĩa là không tuân thủ tiêu chuẩn C, nhưng gần như chắc chắn đó là một vấn đề cần được sửa chữa.

Điểm mấu chốt: while (1)while(2) gần như chắc chắn có hiệu suất tương tự. Chúng có chính xác cùng một ngữ nghĩa và không có lý do chính đáng nào cho bất kỳ trình biên dịch nào không tạo mã giống hệt nhau.

Và mặc dù nó hoàn toàn hợp pháp cho một trình biên dịch để tạo ra nhanh hơn mã cho while(1)hơn cho while(2), đó là bình đẳng pháp lý cho một trình biên dịch để tạo ra nhanh hơn mã cho while(1)hơn cho người khác xảy ra while(1)trong cùng một chương trình.

(Có một câu hỏi khác tiềm ẩn trong câu hỏi mà bạn đã hỏi: Làm thế nào để bạn đối phó với một người phỏng vấn khăng khăng về một điểm kỹ thuật không chính xác. Đó có thể là một câu hỏi hay cho trang web Workplace ).


8
"Trong trường hợp này, các biểu thức hằng số (ẩn) có liên quan là 1! = 0 và 2! = 0, cả hai đều đánh giá giá trị int 1" ... Điều này quá phức tạp và không chính xác. Tiêu chuẩn chỉ đơn giản nói rằng biểu thức điều khiển whilephải là loại vô hướng và thân vòng lặp được lặp lại cho đến khi biểu thức so sánh bằng 0. Nó không nói rằng có một ẩn expr != 0được đánh giá ... sẽ yêu cầu kết quả của rằng - 0 hoặc 1 - lần lượt được so sánh với 0, ad infinitum. Không, biểu thức được so sánh với 0, nhưng so sánh đó không tạo ra giá trị. PS tôi nâng cấp.
Jim Balter

3
@JimBalter: Tôi thấy quan điểm của bạn và tôi sẽ cập nhật câu trả lời của mình để giải quyết nó. Tuy nhiên, điều tôi muốn nói là từ ngữ của tiêu chuẩn "... cho đến khi biểu thức kiểm soát so sánh bằng 0" ngụ ý việc đánh giá <expr> == 0; đó là những gì "so sánh bằng 0" có nghĩa là C. Sự so sánh đó là một phần của ngữ nghĩa của whilevòng lặp. Không có hàm ý, trong tiêu chuẩn hoặc trong câu trả lời của tôi, rằng kết quả cần phải được so sánh với 0một lần nữa. (Đáng lẽ tôi nên viết ==chứ không phải !=.) Nhưng phần câu trả lời của tôi không rõ ràng và tôi sẽ cập nhật nó.
Keith Thompson

1
"" So sánh bằng 0 "có nghĩa là trong C" - nhưng ngôn ngữ đó nằm trong tiêu chuẩn , không phải trong C ... việc triển khai thực hiện so sánh, nó không tạo ra so sánh ngôn ngữ C. Bạn viết "cả hai đánh giá vào giá trị int 1" - nhưng không có đánh giá nào như vậy từng xảy ra. Nếu bạn nhìn vào các mã được tạo cho while (2), while (pointer), while (9.67), do ngây thơ nhất, trình biên dịch được tối ưu hóa, bạn sẽ không thấy bất kỳ mã được tạo mà sản lượng 0hoặc 1. "Tôi nên viết == chứ không phải! =" - không, điều đó sẽ không có ý nghĩa gì.
Jim Balter

2
@JimBalter: Hừm. Tôi không có ý đề nghị rằng "so sánh bằng 0" ngụ ý sự tồn tại của ... == 0biểu thức C. Quan điểm của tôi là cả "so sánh bằng 0" được yêu cầu bởi mô tả các whilevòng lặp tiêu chuẩn và một x == 0biểu thức rõ ràng đều ngụ ý một cách hợp lý cùng một hoạt động. Và tôi nghĩ rằng một trình biên dịch C ngây thơ đau đớn có thể tạo mã tạo ra intgiá trị 0hoặc 1cho bất kỳ whilevòng lặp nào - mặc dù tôi không tin bất kỳ trình biên dịch thực tế nào lại khá ngây thơ.
Keith Thompson

12
Lưu ý: Đây đã là một nơi làm việc câu hỏi: workplace.stackexchange.com/questions/4314/...
Joe

141

Đợi tí. Người phỏng vấn, anh ta có giống anh chàng này không?

nhập mô tả hình ảnh ở đây

Thật tệ khi bản thân người phỏng vấn đã thất bại trong cuộc phỏng vấn này, điều gì sẽ xảy ra nếu các lập trình viên khác tại công ty này đã "vượt qua" bài kiểm tra này?

Không. Đánh giá các báo cáo 1 == 02 == 0 phải nhanh như nhau. Chúng ta có thể tưởng tượng việc triển khai trình biên dịch kém trong đó cái này có thể nhanh hơn cái kia. Nhưng không lý do chính đáng tại sao người này nên nhanh hơn người kia.

Ngay cả khi có một số trường hợp mơ hồ khi tuyên bố là đúng, các lập trình viên không nên được đánh giá dựa trên kiến ​​thức về những điều tối nghĩa (và trong trường hợp này là đáng sợ). Đừng lo lắng về cuộc phỏng vấn này, cách tốt nhất ở đây là bỏ đi.

Disclaimer: Đây KHÔNG phải là phim hoạt hình Dilbert gốc. Đây chỉ đơn thuần là một bản mashup .


6
Điều này sẽ rất buồn cười, nếu nó cũng chứa một câu trả lời cho câu hỏi.
Cody Grey

không nhưng thực sự, tất cả chúng ta đều có thể tưởng tượng khá dễ dàng rằng tất cả các trình biên dịch được viết bởi các công ty nghiêm túc sẽ tạo ra mã hợp lý. hãy lấy "trường hợp không được tối ưu hóa" / O0, có thể nó sẽ kết thúc giống như anatolyg đã đăng. Sau đó là câu hỏi của CPU, cmptoán hạng sẽ chạy trong ít chu kỳ so sánh 1 đến 0 hơn 2 đến 0? Cần bao nhiêu chu kỳ để thực hiện cmp nói chung? nó có biến theo mẫu bit không? chúng có các mẫu bit "phức tạp" hơn làm chậm cmpkhông? Tôi không biết cá nhân. bạn có thể tưởng tượng một triển khai siêu ngu ngốc kiểm tra từng chút một từ hạng 0 đến n (ví dụ n = 31).
v.oddou

5
Đó cũng là quan điểm của tôi: cmptoán hạng phải nhanh như nhau trong 1 và 200. Có lẽ chúng ta có thể tưởng tượng các triển khai ngu ngốc trong trường hợp này không phải là trường hợp. Nhưng chúng ta có thể tưởng tượng một triển khai phi ngu ngốc ở đâu while(1)nhanh hơn while(200)không? Tương tự như vậy, nếu trong một số thời kỳ tiền sử, việc triển khai duy nhất có sẵn là ngu ngốc như vậy, chúng ta có nên ầm ĩ về nó ngày hôm nay không? Tôi không nghĩ vậy, đây là cuộc nói chuyện của ông chủ tóc nhọn, và một viên ngọc thực sự ở đó!
janos

@ v.ouddou "toán hạng cmp sẽ chạy trong ít chu kỳ so sánh 1 đến 0 hơn 2" - Không. Bạn nên tìm hiểu chu kỳ là gì. "Tôi không biết cá nhân. Bạn có thể tưởng tượng một triển khai siêu ngu ngốc kiểm tra từng chút một từ hạng 0 đến n" - hay nói cách khác, vẫn khiến người phỏng vấn trở thành một kẻ ngốc không biết gì. Và tại sao phải lo lắng về việc kiểm tra từng chút một? Việc thực hiện có thể là một người đàn ông trong một hộp quyết định nghỉ trưa giữa lúc đánh giá chương trình của bạn.
Jim Balter

79

Giải thích của bạn là chính xác. Đây dường như là một câu hỏi kiểm tra sự tự tin của bạn bên cạnh kiến ​​thức kỹ thuật.

Nhân tiện, nếu bạn trả lời

Cả hai đoạn mã đều nhanh như nhau, vì cả hai đều mất thời gian vô hạn để hoàn thành

người phỏng vấn sẽ nói

Nhưng while (1) có thể làm nhiều lần lặp lại mỗi giây; bạn có thể giải thích lý do tại sao? (điều này là vô nghĩa; kiểm tra lại sự tự tin của bạn)

Vì vậy, bằng cách trả lời như bạn đã làm, bạn đã tiết kiệm được một chút thời gian mà nếu không bạn sẽ lãng phí khi thảo luận về câu hỏi tồi tệ này.


Dưới đây là mã ví dụ được tạo bởi trình biên dịch trên hệ thống của tôi (MS Visual Studio 2012), với tối ưu hóa bị tắt:

yyy:
    xor eax, eax
    cmp eax, 1     (or 2, depending on your code)
    je xxx
    jmp yyy
xxx:
    ...

Với tối ưu hóa được bật:

xxx:
    jmp xxx

Vì vậy, mã được tạo ra là hoàn toàn giống nhau, ít nhất là với một trình biên dịch tối ưu hóa.


28
Mã này thực sự là những gì trình biên dịch xuất ra trên hệ thống của tôi. Tôi đã không làm cho nó lên.
anatolyg

10
icepack "Toán hạng trong khi thuộc loại boolean" - hoàn toàn vô nghĩa. Bạn có phải là người phỏng vấn? Tôi đề nghị bạn nên làm quen với ngôn ngữ C và tiêu chuẩn của nó trước khi đưa ra yêu cầu như vậy.
Jim Balter

29
"Tôi đã không làm cho nó lên." - Xin đừng chú ý đến túi nước đá, người đang nói chuyện vô nghĩa. C không có kiểu boolean (nó có _Bool trong stdbool.h, nhưng điều đó không giống nhau, và ngữ nghĩa của whiletừ trước đó) và toán hạng whilekhông phải là boolean hoặc _Bool hoặc bất kỳ loại cụ thể nào khác. Toán hạng của whilecó thể là bất kỳ biểu thức nào ... trong khi đó dừng ở 0 và tiếp tục ở mức 0.
Jim Balter

36
"Cả hai đoạn mã đều nhanh như nhau, vì cả hai đều mất thời gian vô hạn để hoàn thành" khiến tôi nghĩ về một điều thú vị. Cách duy nhất để chấm dứt một vòng lặp vô hạn sẽ là một bit bị lật bởi một hạt tích điện hoặc phần cứng bị lỗi: thay đổi câu lệnh từ while (00000001) {}thành while (00000000) {}. Càng nhiều bit đúng, bạn càng có ít cơ hội chuyển giá trị thành false. Đáng buồn thay, 2 cũng chỉ có một bit đúng. 3, tuy nhiên, sẽ chạy lâu hơn đáng kể. Điều này cũng chỉ áp dụng cho trình biên dịch không phải lúc nào cũng tối ưu hóa điều này (VC ++).
Jonathan Dickinson

8
@ mr5 không. Để một chút lật để thực sự dẫn đến một cái gì đó như thế này, bạn đang nói về thời gian thực hiện trong hàng chục ngàn năm. Chỉ là một thử nghiệm suy nghĩ. Nếu bạn đến từ một cuộc đua bất tử, bạn có thể muốn sử dụng -1 để ngăn việc lật bit ảnh hưởng đến chương trình của bạn.
Jonathan Dickinson

60

Giải thích có khả năng nhất cho câu hỏi là người phỏng vấn nghĩ rằng bộ xử lý kiểm tra từng bit của các số, từng cái một, cho đến khi nó đạt giá trị khác không:

1 = 00000001
2 = 00000010

Nếu "bằng không?" thuật toán bắt đầu từ phía bên phải của số và phải kiểm tra từng bit cho đến khi đạt đến một bit khác không, while(1) { }vòng lặp sẽ phải kiểm tra gấp đôi số bit trên mỗi lần lặp so với while(2) { }vòng lặp.

Điều này đòi hỏi một mô hình tinh thần rất sai về cách thức máy tính hoạt động, nhưng nó có logic bên trong riêng. Một cách để kiểm tra sẽ được hỏi nếu while(-1) { }hay while(3) { }sẽ là như nhau nhanh chóng, hoặc nếu while(32) { }sẽ thậm chí chậm hơn .


39
Tôi cho rằng sự hiểu sai của người phỏng vấn sẽ giống như "2 là một int cần được chuyển đổi thành boolean để được sử dụng trong một biểu thức có điều kiện, trong khi 1 đã là boolean."
Russell Borogove

7
Và nếu thuật toán so sánh bắt đầu từ bên trái, thì đó là cách khác.
Paŭlo Ebermann

1
+1, đó chính xác là những gì tôi nghĩ. bạn hoàn toàn có thể tưởng tượng ai đó tin rằng về cơ bản, cmpthuật toán của CPU là kiểm tra bit tuyến tính với lối ra vòng lặp đầu tiên về sự khác biệt đầu tiên.
v.oddou

1
@PeterCordes "Tôi chưa bao giờ nghe ai (ngoài bạn) lập luận rằng -O0đầu ra của gcc hoặc clang không đủ nghĩa đen." Tôi chưa bao giờ nói điều đó và tôi không có ý nghĩ gì cả. Bạn phải đọc sai tôi. Tôi không nghĩ rằng những gì MSVC tạo ra là vui nhộn.
blubberdiblub

1
@PeterCordes Tôi đã sai, trong MSVC, một điểm dừng trên while(1)không bị phá vỡ trước vòng lặp, nhưng trên biểu thức. Nhưng nó vẫn sụp đổ bên trong vòng lặp khi tối ưu hóa biểu thức đi. Lấy mã này với rất nhiều nghỉ. Trong chế độ gỡ lỗi không tối ưu hóa, bạn nhận được điều này . Khi tối ưu hóa, nhiều điểm dừng rơi vào nhau hoặc thậm chí tràn vào chức năng tiếp theo (IDE hiển thị các điểm dừng kết quả trong khi gỡ lỗi) - phân tách tương ứng .
blubberdiblub

32

Tất nhiên tôi không biết ý định thực sự của người quản lý này, nhưng tôi đề xuất một quan điểm hoàn toàn khác: Khi thuê một thành viên mới vào một nhóm, thật hữu ích khi biết cách anh ấy phản ứng với các tình huống xung đột.

Họ đẩy bạn vào cuộc xung đột. Nếu điều này là đúng, họ thông minh và câu hỏi rất hay. Đối với một số ngành, như ngân hàng, việc đăng vấn đề của bạn lên Stack Overflow có thể là một lý do để từ chối.

Nhưng tất nhiên tôi không biết, tôi chỉ đề xuất một lựa chọn.


Nó thực sự xuất sắc nhưng trong khi (2) so với while (1) rõ ràng được lấy từ truyện tranh Dilbert. Nó không thể được phát minh bởi ai đó trong suy nghĩ đúng đắn của mình (làm thế nào để bất cứ ai nghĩ ra trong khi (2) là một điều có thể để viết bằng mọi cách?). Nếu giả thuyết của bạn là đúng, chắc chắn bạn sẽ đưa ra một vấn đề độc đáo đến mức bạn có thể google cho nó. Giống như "trong khi (0xf00b442) chậm hơn so với trong khi (1)", làm thế nào ngân hàng sẽ tìm thấy câu hỏi của người giám sát? Bạn có cho rằng họ là NSA và có quyền truy cập vào keyscore không?
v.oddou

25

Tôi nghĩ rằng manh mối sẽ được tìm thấy trong "yêu cầu của người quản lý cấp cao". Người này rõ ràng đã ngừng lập trình khi anh ta trở thành người quản lý và sau đó anh ta / cô ta phải mất vài năm để trở thành người quản lý cấp cao. Không bao giờ mất hứng thú với lập trình, nhưng không bao giờ viết một dòng kể từ những ngày đó. Vì vậy, tài liệu tham khảo của ông không phải là "bất kỳ trình biên dịch tử tế nào ngoài kia" như một số câu trả lời đề cập, mà là "trình biên dịch mà người này đã làm việc với 20-30 năm trước".

Vào thời điểm đó, các lập trình viên đã dành một tỷ lệ đáng kể thời gian của họ để thử các phương pháp khác nhau để làm cho mã của họ nhanh hơn và hiệu quả hơn vì thời gian CPU của 'máy tính trung tâm' rất có giá trị. Như mọi người đã viết trình biên dịch. Tôi đoán rằng trình biên dịch một và duy nhất mà công ty của anh ta đã có sẵn tại thời điểm đó được tối ưu hóa trên cơ sở 'các câu lệnh thường gặp có thể được tối ưu hóa' và mất một chút phím tắt khi gặp một lúc (1) và đánh giá mọi thứ khác, bao gồm một thời gian (2). Có một kinh nghiệm như vậy có thể giải thích vị trí của anh ấy và sự tự tin của anh ấy trong đó.

Cách tiếp cận tốt nhất để giúp bạn được thuê có lẽ là một cách cho phép người quản lý cấp cao được mang đi và giảng cho bạn 2-3 phút về "những ngày tốt đẹp của lập trình" trước BẠN trơn tru dẫn anh ấy về phía đối tượng phỏng vấn tiếp theo. (Thời điểm tốt rất quan trọng ở đây - quá nhanh và bạn đang làm gián đoạn câu chuyện - quá chậm và bạn bị gắn mác là một người không đủ tập trung). Hãy nói với anh ấy vào cuối cuộc phỏng vấn rằng bạn sẽ rất thích tìm hiểu thêm về chủ đề này.


19

Bạn nên hỏi anh ấy làm thế nào anh ấy đi đến kết luận đó. Dưới bất kỳ trình biên dịch tử tế nào ngoài đó, hai trình biên dịch theo cùng một hướng dẫn asm. Vì vậy, anh ấy nên nói với bạn trình biên dịch là bắt đầu. Và ngay cả như vậy, bạn sẽ phải biết rất rõ về trình biên dịch và nền tảng để thậm chí đưa ra một phỏng đoán có lý thuyết. Và cuối cùng, nó không thực sự quan trọng trong thực tế, vì có các yếu tố bên ngoài khác như phân mảnh bộ nhớ hoặc tải hệ thống sẽ ảnh hưởng đến vòng lặp nhiều hơn chi tiết này.


14
@GKFX Nếu bạn đã đưa ra câu trả lời của mình và họ nói với bạn rằng bạn sai thì không có lý do gì bạn không thể yêu cầu họ giải thích lý do. Nếu Anatolyg đúng và đó là một bài kiểm tra sự tự tin của bạn thì bạn nên giải thích lý do tại sao bạn trả lời theo cách bạn đã làm và hỏi họ như vậy.
P.Turpie

Ý tôi là điều đầu tiên bạn nói với họ. Không thể là "Tại sao x nhanh hơn?" "Tôi không biết; tại sao x nhanh hơn?". Rõ ràng, đã trả lời đúng, bạn có thể hỏi.
GKFX

18

Vì câu hỏi này, tôi nên thêm rằng tôi nhớ Doug Gwyn từ Ủy ban C viết rằng một số trình biên dịch C ban đầu không có trình tối ưu hóa sẽ tạo ra một bài kiểm tra lắp ráp cho while(1)(so sánh vớifor(;;) không có nó).

Tôi sẽ trả lời người phỏng vấn bằng cách đưa ra ghi chú lịch sử này và sau đó nói rằng ngay cả khi tôi sẽ rất ngạc nhiên bất kỳ trình biên dịch nào đã làm điều này, một trình biên dịch có thể có:

  • không có trình tối ưu hóa, trình biên dịch sẽ tạo một bài kiểm tra cho cả hai while(1)while(2)
  • với trình tối ưu hóa, trình biên dịch được hướng dẫn để tối ưu hóa (với bước nhảy vô điều kiện) tất cả while(1)vì chúng được coi là thành ngữ. Điều này sẽ để lại while(2)một bài kiểm tra và do đó làm cho sự khác biệt hiệu suất giữa hai.

Tất nhiên tôi sẽ thêm vào người phỏng vấn rằng không xem xét while(1)while(2)cấu trúc tương tự là dấu hiệu của tối ưu hóa chất lượng thấp vì đây là các cấu trúc tương đương.


10

Một câu hỏi khác sẽ là xem bạn có đủ can đảm để nói với người quản lý của mình rằng anh ấy / cô ấy sai không! Và làm thế nào nhẹ nhàng bạn có thể giao tiếp nó.

Bản năng đầu tiên của tôi sẽ là tạo đầu ra lắp ráp để cho người quản lý thấy rằng bất kỳ trình biên dịch tử tế nào cũng sẽ chăm sóc nó và nếu nó không làm như vậy, bạn sẽ gửi bản vá tiếp theo cho nó :)


8

Để thấy rất nhiều người đi sâu vào vấn đề này, hãy chỉ ra chính xác lý do tại sao điều này rất có thể là một thử nghiệm để xem bạn muốn tối ưu hóa mọi thứ nhanh như thế nào .

Câu trả lời của tôi sẽ là; nó không quan trọng lắm, tôi tập trung vào vấn đề kinh doanh mà chúng tôi đang giải quyết. Rốt cuộc, đó là những gì tôi sẽ được trả tiền cho.

Hơn nữa, tôi sẽ chọn while(1) {}vì nó phổ biến hơn và các đồng đội khác sẽ không cần dành thời gian để tìm hiểu lý do tại sao một người nào đó lại đi với số lượng cao hơn 1.

Bây giờ đi viết một số mã. ;-)


1
Trừ khi bạn được trả tiền để tối ưu hóa một số mã thời gian thực mà bạn cần cạo chỉ 1 hoặc 2 mili giây để phù hợp với nhu cầu thời gian chạy của nó. Tất nhiên đó là một công việc cho trình tối ưu hóa, một số người sẽ nói - đó là nếu bạn có một trình tối ưu hóa cho kiến ​​trúc của mình.
Neowizard

6

Nếu bạn lo lắng về việc tối ưu hóa, bạn nên sử dụng

for (;;)

bởi vì điều đó không có bài kiểm tra (chế độ yếm thế)


2
Đó là lý do tại sao nên sử dụng while(2)nó, nó sẽ nhường chỗ cho tối ưu hóa, sau đó bạn chỉ cần chuyển sang for (;;)khi bạn đã sẵn sàng để tăng hiệu suất.
Groo

5

Dường như với tôi đây là một trong những câu hỏi phỏng vấn hành vi được che đậy như một câu hỏi kỹ thuật. Một số công ty làm điều này - họ sẽ hỏi một câu hỏi kỹ thuật khá dễ dàng để bất kỳ lập trình viên có thẩm quyền nào trả lời, nhưng khi người được phỏng vấn trả lời đúng, người phỏng vấn sẽ nói với họ rằng họ đã sai.

Công ty muốn xem bạn sẽ phản ứng thế nào trong tình huống này. Bạn có ngồi im lặng và không thúc đẩy rằng câu trả lời của bạn là chính xác, do nghi ngờ bản thân hoặc sợ làm phiền người phỏng vấn? Hay bạn sẵn sàng thách thức một người có thẩm quyền mà bạn biết là sai? Họ muốn xem liệu bạn có sẵn sàng đứng lên cho niềm tin của mình không, và liệu bạn có thể làm điều đó một cách khéo léo và tôn trọng.


3

Tôi đã từng lập trình C và mã hội trở lại khi loại vô nghĩa này có thể đã tạo ra sự khác biệt. Khi nó đã làm cho một sự khác biệt, chúng tôi đã viết nó trong hội.

Nếu tôi được hỏi câu hỏi đó, tôi sẽ lặp lại câu nói nổi tiếng năm 1974 của Donald Knuth về tối ưu hóa sớm và đi bộ nếu người phỏng vấn không cười và tiếp tục.


1
Ông cũng nói rằng "Trong các ngành kỹ thuật đã thành lập, sự cải thiện 12%, dễ dàng đạt được, không bao giờ được coi là cận biên và tôi tin rằng quan điểm tương tự sẽ chiếm ưu thế trong công nghệ phần mềm", tôi nghĩ rằng bạn đi bộ là không chính đáng.
Alice

3

Có thể người phỏng vấn đặt ra câu hỏi ngớ ngẩn như vậy một cách có chủ ý và muốn bạn kiếm được 3 điểm:

  1. Lý luận cơ bản. Cả hai vòng lặp là vô hạn, thật khó để nói về hiệu suất.
  2. Kiến thức về mức độ tối ưu hóa. Anh ấy muốn nghe từ bạn nếu bạn để trình biên dịch thực hiện bất kỳ tối ưu hóa nào cho bạn, nó sẽ tối ưu hóa điều kiện, đặc biệt là nếu khối không trống.
  3. Kiến thức về kiến ​​trúc vi xử lý. Hầu hết các kiến ​​trúc đều có một lệnh CPU đặc biệt để so sánh với 0 (trong khi không nhất thiết phải nhanh hơn).

2

Đây là một vấn đề: Nếu bạn thực sự viết một chương trình và đo tốc độ của nó, tốc độ của cả hai vòng có thể khác nhau! Đối với một số so sánh hợp lý:

unsigned long i = 0;
while (1) { if (++i == 1000000000) break; }

unsigned long i = 0;
while (2) { if (++i == 1000000000) break; }

với một số mã được thêm vào để in thời gian, một số hiệu ứng ngẫu nhiên như cách vòng lặp được định vị trong một hoặc hai dòng bộ đệm có thể tạo ra sự khác biệt. Một vòng lặp có thể hoàn toàn nằm trong một dòng bộ đệm hoặc khi bắt đầu một dòng bộ đệm, hoặc nó có thể sắp xếp hai dòng bộ đệm. Và kết quả là, bất cứ điều gì người phỏng vấn tuyên bố là nhanh nhất thực sự có thể là nhanh nhất - bởi sự trùng hợp.

Trường hợp xấu nhất: Trình biên dịch tối ưu hóa không tìm ra vòng lặp làm gì, nhưng chỉ ra rằng các giá trị được tạo ra khi vòng lặp thứ hai được thực hiện giống như vòng lặp đầu tiên được tạo ra. Và tạo mã đầy đủ cho vòng lặp đầu tiên, nhưng không phải cho vòng thứ hai.


1
Lý do "dòng bộ đệm" sẽ chỉ hoạt động trên một con chip có bộ đệm cực kỳ nhỏ.
sharptooth

10
Đây là bên cạnh điểm. Các câu hỏi về tốc độ giả định "tất cả những thứ khác như nhau".
Jim Balter

6
@JimBalter: Đây không phải là một câu hỏi về tốc độ, nó là một câu hỏi về một cuộc tranh luận với một người phỏng vấn. Và khả năng thực hiện một bài kiểm tra thực tế có thể chứng minh người phỏng vấn "đúng" - vì những lý do không liên quan gì đến lập luận của anh ta mà chỉ là sự trùng hợp thuần túy. Điều đó sẽ đặt bạn vào một tình huống xấu hổ nếu bạn cố chứng minh anh ấy đã sai.
gnasher729

1
@ gnasher729 Tất cả các lý lẽ hợp lý sang một bên, trường hợp trùng hợp mà bạn nói về sẽ đáng xem xét. Nhưng vẫn mù quáng tin một trường hợp như vậy tồn tại không chỉ ngây thơ mà ngu ngốc. Miễn là bạn không giải thích điều gì, làm thế nào hoặc tại sao điều đó sẽ xảy ra thì câu trả lời này là vô ích.
dùng568109

4
@ gnasher729 "Đây không phải là câu hỏi về tốc độ" - Tôi sẽ không tranh luận về những người sử dụng các kỹ thuật tu từ không trung thực.
Jim Balter

2

Cả hai đều bằng nhau - giống nhau.

Theo thông số kỹ thuật, mọi thứ không phải là 0 đều được coi là đúng, vì vậy ngay cả khi không có bất kỳ tối ưu hóa nào, và một trình biên dịch tốt sẽ không tạo ra bất kỳ mã nào trong khi (1) hoặc while (2). Trình biên dịch sẽ tạo ra một kiểm tra đơn giản cho != 0.


@djechlin - vì cả hai đều mất 1 chu kỳ cpu.
ChúKing 23/07 '

Trình biên dịch liên tục gập nó, vì vậy nó thậm chí không được đánh giá trong thời gian chạy.
PaulHK

2

Đánh giá bằng lượng thời gian và công sức mọi người đã bỏ ra để kiểm tra, chứng minh và trả lời câu hỏi rất thẳng này Id nói rằng cả hai đều được thực hiện rất chậm bằng cách đặt câu hỏi.

Và vì vậy để dành nhiều thời gian hơn cho nó ...

"trong khi (2)" là vô lý, bởi vì,

"while (1)" và "while (true)" trong lịch sử được sử dụng để tạo một vòng lặp vô hạn dự kiến ​​"phá vỡ" sẽ được gọi ở một giai đoạn nào đó bên trong vòng lặp dựa trên một điều kiện chắc chắn sẽ xảy ra.

"1" chỉ đơn giản là ở đó để luôn luôn đánh giá là đúng và do đó, để nói "while (2)" cũng ngớ ngẩn như nói "while (1 + 1 == 2)" cũng sẽ đánh giá là đúng.

Và nếu bạn muốn hoàn toàn ngớ ngẩn, chỉ cần sử dụng: -

while (1 + 5 - 2 - (1 * 3) == 0.5 - 4 + ((9 * 2) / 4)) {
    if (succeed())
        break;
}

Tôi muốn nghĩ rằng lập trình viên của bạn đã tạo ra một lỗi đánh máy không ảnh hưởng đến việc chạy mã, nhưng nếu anh ta cố tình sử dụng "2" để trở nên kỳ lạ thì hãy sa thải anh ta trước khi anh ta đặt mã lạ vào mã của bạn. đọc và làm việc với.


Việc khôi phục bạn thực hiện hoàn nguyên chỉnh sửa bởi người dùng rất cao. Những người này thường biết rất rõ các chính sách và họ ở đây để dạy chúng cho bạn. Tôi tìm thấy dòng cuối cùng của bài viết của bạn thêm không có gì hữu ích cho bài viết của bạn. Ngay cả khi tôi nhận được trò đùa mà tôi rõ ràng là mất tích, tôi sẽ coi đó là quá trò chuyện, không đáng để thêm đoạn.
Palec

@Palec: Cảm ơn bạn đã bình luận. Tôi thấy rằng cùng một người đã chỉnh sửa nhiều bài viết của tôi, chủ yếu chỉ để loại bỏ các dấu hiệu. Vì vậy, tôi nghĩ rằng anh ta chỉ là một kẻ troll danh tiếng, và do đó danh tiếng của anh ta. Các diễn đàn trực tuyến đã làm cạn kiệt ngôn ngữ - và các cuộc tán tỉnh thông thường - đến mức chúng tôi không còn ký các bài viết của mình nữa? có lẽ tôi là một trường học nhỏ tuổi nhưng có vẻ thô lỗ khi bỏ qua địa ngục và tạm biệt. Chúng tôi đang sử dụng các ứng dụng, nhưng chúng tôi vẫn là con người.
ekerner

1
Trên Stack Exchange , lời chào, khẩu hiệu, cảm ơn, vv không được chào đón . Điều tương tự được đề cập trong trung tâm trợ giúp , đặc biệt theo hành vi dự kiến . Không có phần nào của Stack Exchange , thậm chí cả Stack Overflow , là một diễn đàn - chúng là các trang web Hỏi & Đáp. Chỉnh sửa là một trong những khác biệt. Ngoài ra các bình luận chỉ nên phục vụ để cung cấp phản hồi về bài đăng, không dành cho thảo luận ( Trò chuyện chồng chéo ). Và có nhiều cách khác Q & A khác với một diễn đàn. Thêm vào đó trong trung tâm trợ giúp và trên Meta Stack Overflow .
Palec

Lưu ý rằng khi bạn có hơn 2000 đại diện (đặc quyền chỉnh sửa), bạn sẽ không nhận được nhiều đại diện hơn từ các chỉnh sửa. Khi nghi ngờ tại sao và chỉnh sửa bạn không đồng ý với bài đăng của bạn hoặc bạn thấy hành vi sai trái của ai đó, hãy hỏi về Meta Stack Overflow . Nếu biên tập viên đã làm sai, họ có thể được thông báo bởi một mod (có thể họ không nhận ra) hoặc thậm chí bị trừng phạt bằng cách nào đó (nếu hành vi đó là cố ý độc hại). Nếu không, bạn nhận được con trỏ để giải thích tại sao chỉnh sửa / hành vi là chính xác. Rollback không cần thiết clutter lịch sử sửa đổi và có thể đưa bạn vào cuộc chiến rollback. Tôi chỉ quay lại khi thực sự chắc chắn rằng chỉnh sửa không chính xác.
Palec

Cuối cùng về việc ký, chào, trên mạng: Có vẻ thô lỗ khi không bao gồm các thủ tục này, nhưng nó làm tăng tín hiệu cho tỷ lệ nhiễu và không có thông tin nào bị mất. Bạn có thể chọn bất kỳ biệt danh nào bạn muốn, đó là chữ ký của bạn. Ở hầu hết các nơi bạn cũng có avatar của mình.
Palec

1

Điều đó phụ thuộc vào trình biên dịch.

Nếu nó tối ưu hóa mã, hoặc nếu nó đánh giá 1 và 2 thành đúng với cùng một số lệnh cho một tập lệnh cụ thể, tốc độ thực thi sẽ như nhau.

Trong trường hợp thực tế, nó sẽ luôn nhanh như nhau, nhưng có thể tưởng tượng một trình biên dịch cụ thể và một hệ thống cụ thể khi điều này sẽ được đánh giá khác nhau.

Ý tôi là: đây không thực sự là một câu hỏi liên quan đến ngôn ngữ (C).


0

Vì mọi người đang tìm cách trả lời câu hỏi này muốn vòng lặp nhanh nhất, nên tôi đã trả lời rằng cả hai đều được biên dịch như nhau thành cùng một mã lắp ráp, như đã nêu trong các câu trả lời khác. Tuy nhiên, bạn có thể đề xuất với người phỏng vấn bằng cách sử dụng 'unrolling'; a do {} vòng lặp while thay vì vòng lặp while.

Thận trọng: Bạn cần đảm bảo rằng vòng lặp ít nhất sẽ luôn chạy một lần .

Các vòng lặp nên có một điều kiện phá vỡ bên trong.

Ngoài ra, đối với loại vòng lặp đó, cá nhân tôi thích sử dụng do {} while (42) vì bất kỳ số nguyên nào, ngoại trừ 0, sẽ thực hiện công việc.


Tại sao anh ta lại đề xuất một vòng lặp while {}? Trong khi (1) (hoặc while (2)) làm điều tương tự.
Catsunami

làm trong khi loại bỏ một bước nhảy thêm để hiệu suất tốt hơn. Tất nhiên trong trường hợp bạn biết rằng vòng lặp sẽ được thực thi ít nhất một lần
Antonin GAVREL

0

Câu trả lời rõ ràng là: như đã đăng, cả hai đoạn sẽ chạy một vòng lặp vô hạn bận rộn như nhau, làm cho chương trình chậm vô hạn .

Mặc dù việc xác định lại các từ khóa C là các macro về mặt kỹ thuật sẽ có hành vi không xác định, nhưng đó là cách duy nhất tôi có thể nghĩ để tạo ra đoạn mã nhanh chóng: bạn có thể thêm dòng này lên trên 2 đoạn:

#define while(x) sleep(x);

nó thực sự sẽ làm while(1)nhanh gấp đôi (hoặc một nửa chậm) while(2).


@MaxB: thực sự là thủ thuật vĩ mô phải thậm chí còn méo hơn nữa. Tôi nghĩ rằng phiên bản mới sẽ hoạt động, mặc dù không được đảm bảo bởi Tiêu chuẩn C.
chqrlie

-4

Lý do duy nhất tôi có thể nghĩ tại sao while(2)sẽ chậm hơn là:

  1. Mã tối ưu hóa vòng lặp để

    cmp eax, 2

  2. Khi phép trừ xảy ra, về cơ bản bạn đang trừ

    a. 00000000 - 00000010 cmp eax, 2

    thay vì

    b. 00000000 - 00000001 cmp eax, 1

cmpchỉ đặt cờ và không đặt kết quả. Vì vậy, trên các bit có ý nghĩa ít nhất chúng ta biết nếu chúng ta cần vay hay không với b . Trong khi đó với một bạn phải thực hiện hai phép trừ trước khi bạn vay tiền.


15
cmp sẽ mất 1 chu kỳ cpu bất kể trong cả hai trường hợp.
ChúKing 23/07 '

8
Mã đó sẽ không chính xác. Mã chính xác sẽ tải 2 hoặc 1 vào đăng ký eax, sau đó so sánh eax với 0.
gnasher729
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.