简体   繁体   English

哪个更快:while(1)或while(2)?

[英]Which is faster: while(1) or while(2)?

This was an interview question asked by a senior manager. 这是一位高级经理提出的面试问题。

Which is faster? 哪个更快?

while(1) {
    // Some code
}

or 要么

while(2) {
    //Some code
}

I said that both have the same execution speed, as the expression inside while should finally evaluate to true or false . 我说,都具有相同的执行速度,因为里面的表现while应该最终评估为truefalse In this case, both evaluate to true and there are no extra conditional instructions inside the while condition. 在这种情况下,两者都计算为truewhile条件中没有额外的条件指令。 So, both will have the same speed of execution and I prefer while (1). 因此,两者都具有相同的执行速度,而我更喜欢(1)。

But the interviewer said confidently: "Check your basics. while(1) is faster than while(2) ." 但是采访者自信地说:“检查你的基础知识。 while(1)while(2)更快。” (He was not testing my confidence) (他没有测试我的信心)

Is this true? 这是真的?

See also: Is "for(;;)" faster than "while (TRUE)"? 另请参阅: “for(;;)”是否比“while(TRUE)”快? If not, why do people use it? 如果没有,为什么人们会使用它?

Both loops are infinite, but we can see which one takes more instructions/resources per iteration. 两个循环都是无限的,但是我们可以看到哪个循环每次迭代需要更多的指令/资源。

Using gcc, I compiled the two following programs to assembly at varying levels of optimization: 使用gcc,我将以下两个程序编译为不同优化级别的程序集:

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


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

Even with no optimizations ( -O0 ), the generated assembly was identical for both programs . 即使没有优化( -O0 ), 生成的程序集对于两个程序都是相同的 Therefore, there is no speed difference between the two loops. 因此,两个循环之间没有速度差异。

For reference, here is the generated assembly (using gcc main.c -S -masm=intel with an optimization flag): 作为参考,这里是生成的程序集(使用gcc main.c -S -masm=intel和优化标志):

With -O0 : 使用-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"

With -O1 : 使用-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"

With -O2 and -O3 (same output): 使用-O2-O3 (相同输出):

    .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"

In fact, the assembly generated for the loop is identical for every level of optimization: 实际上,为循环生成的程序集对于每个优化级别都是相同的:

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

The important bits being: 重要的是:

.L2:
    jmp .L2

I can't read assembly very well, but this is obviously an unconditional loop. 我不能很好地阅读汇编,但这显然是一个无条件的循环。 The jmp instruction unconditionally resets the program back to the .L2 label without even comparing a value against true, and of course immediately does so again until the program is somehow ended. jmp指令无条件地将程序重置为.L2标签,甚至没有将值与true进行比较,当然会立即再次执行,直到程序以某种方式结束。 This directly corresponds to the C/C++ code: 这直接对应于C / C ++代码:

L2:
    goto L2;

Edit: 编辑:

Interestingly enough, even with no optimizations , the following loops all produced the exact same output (unconditional jmp ) in assembly: 有趣的是,即使没有优化 ,以下循环都会在汇编中产生完全相同的输出(无条件jmp ):

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) {}

And even to my amazement: 令我惊讶的是:

#include<math.h>

while(sqrt(7)) {}

while(hypot(3,4)) {}

Things get a little more interesting with user-defined functions: 用户定义的函数使事情变得更有趣:

int x(void) {
    return 1;
}

while(x()) {}


#include<math.h>

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

while(x()) {}

At -O0 , these two examples actually call x and perform a comparison for each iteration. -O0 ,这两个示例实际上调用x并对每次迭代执行比较。

First example (returning 1): 第一个例子(返回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"

Second example (returning sqrt(7) ): 第二个例子(返回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"

However, at -O1 and above, they both produce the same assembly as the previous examples (an unconditional jmp back to the preceding label). 但是,在-O1及以上,它们都产生与前面示例相同的程序集(无条件的jmp返回到前面的标签)。

TL;DR TL; DR

Under GCC, the different loops are compiled to identical assembly. 在GCC下,不同的循环被编译为相同的程序集。 The compiler evaluates the constant values and doesn't bother performing any actual comparison. 编译器会评估常量值,并且不会执行任何实际比较。

The moral of the story is: 这个故事的寓意是:

  • There exists a layer of translation between C++ source code and CPU instructions, and this layer has important implications for performance. C ++源代码和CPU指令之间存在一层转换,这一层对性能有重要影响。
  • Therefore, performance cannot be evaluated by only looking at source code. 因此,仅通过查看源代码无法评估性能。
  • The compiler should be smart enough to optimize such trivial cases. 编译器应该足够聪明以优化这些琐碎的案例。 Programmers should not waste their time thinking about them in the vast majority of cases. 在绝大多数情况下,程序员不应该浪费时间思考它们。

Yes, while(1) is much faster than while(2) , for a human to read! 是的, while(1)while(2)快得多, 人类可以阅读! If I see while(1) in an unfamiliar codebase, I immediately know what the author intended, and my eyeballs can continue to the next line. 如果我在一个不熟悉的代码库中看到while(1) ,我立即知道作者的意图,我的眼球可以继续下一行。

If I see while(2) , I'll probably halt in my tracks and try to figure out why the author didn't write while(1) . 如果我看到while(2) ,我可能会停下来试图找出作者为什么不写while(1) Did the author's finger slip on the keyboard? 作者的手指在键盘上滑动了吗? Do the maintainers of this codebase use while(n) as an obscure commenting mechanism to make loops look different? 这个代码库的维护者是否使用while(n)作为一个模糊的注释机制来使循环看起来不同? Is it a crude workaround for a spurious warning in some broken static analysis tool? 对于某些破碎的静态分析工具中的虚假警告,这是一个粗略的解决方法吗? Or is this a clue that I'm reading generated code? 或者这是我正在阅读生成代码的线索吗? Is it a bug resulting from an ill-advised find-and-replace-all, or a bad merge, or a cosmic ray? 这是一个由于不明智的查找和替换全部,或者是一个糟糕的合并或一个宇宙射线导致的错误? Maybe this line of code is supposed to do something dramatically different. 也许这行代码应该做一些截然不同的事情。 Maybe it was supposed to read while(w) or while(x2) . 也许它应该while(w)while(x2)读取。 I'd better find the author in the file's history and send them a "WTF" email... and now I've broken my mental context. 我最好在文件的历史中找到作者并向他们发送“WTF”电子邮件......现在我已经打破了我的心理背景。 The while(2) might consume several minutes of my time, when while(1) would have taken a fraction of a second! while(2)可能会耗费几分钟的时间, while(1)可能需要几分之一秒!

I'm exaggerating, but only a little. 我夸张了,但只是一点点。 Code readability is really important. 代码可读性非常重要。 And that's worth mentioning in an interview! 这在采访中值得一提!

The existing answers showing the code generated by a particular compiler for a particular target with a particular set of options do not fully answer the question -- unless the question was asked in that specific context ("Which is faster using gcc 4.7.2 for x86_64 with default options?", for example). 显示特定编译器为具有特定选项集的特定目标生成的代码的现有答案不能完全回答问题 - 除非在该特定上下文中询问了问题(“使用gcc 4.7.2 for x86_64更快”使用默认选项?“,例如)。

As far as the language definition is concerned, in the abstract machine while (1) evaluates the integer constant 1 , and while (2) evaluates the integer constant 2 ; 就语言定义而言,在抽象机器中 while (1)计算整数常量1 ,而while (2)计算整数常量2 ; in both cases the result is compared for equality to zero. 在两种情况下,结果都将相等性与零进行比较。 The language standard says absolutely nothing about the relative performance of the two constructs. 语言标准绝对没有说明两种结构的相对性能。

I can imagine that an extremely naive compiler might generate different machine code for the two forms, at least when compiled without requesting optimization. 我可以想象一个非常天真的编译器可能会为这两种形式生成不同的机器代码,至少在编译时没有请求优化。

On the other hand, C compilers absolutely must evaluate some constant expressions at compile time, when they appear in contexts that require a constant expression. 另一方面,C编译器绝对必须在编译时评估一些常量表达式,当它们出现在需要常量表达式的上下文中时。 For example, this: 例如,这个:

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

requires a diagnostic; 需要诊断; a lazy compiler does not have the option of deferring the evaluation of 2+2 until execution time. 延迟编译器没有选择将执行时间推迟到2+2的评估。 Since a compiler has to have the ability to evaluate constant expressions at compile time, there's no good reason for it not to take advantage of that capability even when it's not required. 由于编译器必须能够在编译时评估常量表达式,因此即使不需要,也没有充分的理由不利用该功能。

The C standard ( N1570 6.8.5p4) says that C标准( N1570 6.8.5p4)说明了这一点

An iteration statement causes a statement called the loop body to be executed repeatedly until the controlling expression compares equal to 0. 迭代语句会导致重复执行一个称为循环体的语句,直到控制表达式比较等于0。

So the relevant constant expressions are 1 == 0 and 2 == 0 , both of which evaluate to the int value 0 . 所以相关的常量表达式是1 == 02 == 0 ,两者都计算为int0 (These comparison are implicit in the semantics of the while loop; they don't exist as actual C expressions.) (这些比较隐含在while循环的语义中;它们不作为实际的C表达式存在。)

A perversely naive compiler could generate different code for the two constructs. 一个反常天真的编译器可以为这两个结构生成不同的代码。 For example, for the first it could generate an unconditional infinite loop (treating 1 as a special case), and for the second it could generate an explicit run-time comparison equivalent to 2 != 0 . 例如,对于第一个,它可以生成无条件无限循环(将1视为特殊情况),对于第二个,它可以生成等效于2 != 0的显式运行时比较。 But I've never encountered a C compiler that would actually behave that way, and I seriously doubt that such a compiler exists. 但我从未遇到过实际上会以这种方式运行的C编译器,我非常怀疑这样的编译器是否存在。

Most compilers (I'm tempted to say all production-quality compilers) have options to request additional optimizations. 大多数编译器(我很想说所有生产质量编译器)都可以选择进行额外的优化。 Under such an option, it's even less likely that any compiler would generate different code for the two forms. 在这样的选项下,任何编译器都不太可能为这两种形式生成不同的代码。

If your compiler generates different code for the two constructs, first check whether the differing code sequences actually have different performance. 如果编译器为这两个构造生成不同的代码,请首先检查不同的代码序列是否实际上具有不同的性能。 If they do, try compiling again with an optimization option (if available). 如果是,请尝试使用优化选项再次编译(如果可用)。 If they still differ, submit a bug report to the compiler vendor. 如果它们仍然不同,请向编译器供应商提交错误报告。 It's not (necessarily) a bug in the sense of a failure to conform to the C standard, but it's almost certainly a problem that should be corrected. 它(不一定)是一个不符合C标准意义上的错误,但它几乎肯定是一个应该纠正的问题。

Bottom line: while (1) and while(2) almost certainly have the same performance. 底线: while (1)while(2) 几乎肯定具有相同的性能。 They have exactly the same semantics, and there's no good reason for any compiler not to generate identical code. 它们具有完全相同的语义,并且没有充分的理由让任何编译器不生成相同的代码。

And though it's perfectly legal for a compiler to generate faster code for while(1) than for while(2) , it's equally legal for a compiler to generate faster code for while(1) than for another occurrence of while(1) in the same program. 尽管它是完全合法的编译器生成速度更快的代码while(1)while(2)这是同样的法律对编译器生成速度更快的代码while(1)比另一种发生while(1)在同样的计划。

(There's another question implicit in the one you asked: How do you deal with an interviewer who insists on an incorrect technical point. That would probably be a good question for the Workplace site ). (你问的那个问题隐含着另一个问题:你如何处理一个坚持不正确的技术要点的面试官。这可能是Workplace网站的一个好问题)。

Wait a minute. 等一下。 The interviewer, did he look like this guy? 面试官,他看起来像这个家伙?

在此输入图像描述

It's bad enough that the interviewer himself has failed this interview, what if other programmers at this company have "passed" this test? 面试官本人未能通过这次面试,这很糟糕,如果这家公司的其他程序员“通过”了这个测试呢?

No. Evaluating the statements 1 == 0 and 2 == 0 should be equally fast. 不。评估语句1 == 02 == 0 应该同样快。 We could imagine poor compiler implementations where one might be faster than the other. 我们可以想象糟糕的编译器实现,其中一个可能比另一个更快。 But there's no good reason why one should be faster than the other. 但是没有充分理由说为什么一个人应该比另一个人更快。

Even if there's some obscure circumstance when the claim would be true, programmers should not be evaluated based on knowledge of obscure (and in this case, creepy) trivia. 即使有一些模糊的情况,当声称是真的,程序员也不应该根据模糊(在这种情况下,令人毛骨悚然)的琐事的知识进行评估。 Don't worry about this interview, the best move here is to walk away. 不要担心这次采访,这里最好的举动就是走开。

Disclaimer: This is NOT an original Dilbert cartoon. 免责声明: 这不是原始的Dilbert漫画。 This is merely a mashup . 这只是一个混搭

Your explanation is correct. 你的解释是正确的。 This seems to be a question that tests your self-confidence in addition to technical knowledge. 除了技术知识之外,这似乎是一个测试你的自信心的问题。

By the way, if you answered 顺便问一下,如果你回答

Both pieces of code are equally fast, because both take infinite time to complete 这两段代码同样快,因为两者都需要无限的时间才能完成

the interviewer would say 面试官会说

But while (1) can do more iterations per second; 但是while (1)可以每秒进行更多的迭代; can you explain why? 你能解释一下原因吗? (this is nonsense; testing your confidence again) (这是废话;再次测试你的信心)

So by answering like you did, you saved some time which you would otherwise waste on discussing this bad question. 所以通过像你一样回答,你节省了一些时间,否则你会浪费在讨论这个糟糕的问题上。


Here is an example code generated by the compiler on my system (MS Visual Studio 2012), with optimizations turned off: 以下是我的系统(MS Visual Studio 2012)上的编译器生成的示例代码,关闭了优化:

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

With optimizations turned on: 启用优化后:

xxx:
    jmp xxx

So the generated code is exactly the same, at least with an optimizing compiler. 所以生成的代码完全相同,至少使用优化编译器。

The most likely explanation for the question is that the interviewer thinks that the processor checks the individual bits of the numbers, one by one, until it hits a non-zero value: 这个问题最可能的解释是,面试官认为处理器一个接一个地检查数字的各个位,直到它达到非零值:

1 = 00000001
2 = 00000010

If the "is zero?" 如果“为零?” algorithm starts from the right side of the number and has to check each bit until it reaches a non-zero bit, the while(1) { } loop would have to check twice as many bits per iteration as the while(2) { } loop. 算法从数字的右侧开始,并且必须检查每个位直到它达到非零位, while(1) { }循环必须检查每次迭代的两倍于while(2) { }环。

This requires a very wrong mental model of how computers work, but it does have its own internal logic. 这需要一个非常错误的计算机工作方式的心智模型,但它确实有自己的内部逻辑。 One way to check would be to ask if while(-1) { } or while(3) { } would be equally fast, or if while(32) { } would be even slower . 一种检查方法是询问while(-1) { }while(3) { }是否同样快,或者while(32) { }是否更慢

Of course I do not know the real intentions of this manager, but I propose a completely different view: When hiring a new member into a team, it is useful to know how he reacts to conflict situations. 当然,我不知道这位经理的真实意图,但我提出了一个完全不同的观点:当雇用一名新成员加入团队时,了解他如何应对冲突局势是有用的。

They drove you into conflict. 他们让你陷入冲突。 If this is true, they are clever and the question was good. 如果这是真的,他们很聪明,问题很好。 For some industries, like banking, posting your problem to Stack Overflow could be a reason for rejection. 对于某些行业,例如银行业务,将您的问题发布到Stack Overflow可能是拒绝的原因。

But of course I do not know, I just propose one option. 但我当然不知道,我只提出一个选择。

I think the clue is to be found in "asked by a senior manager". 我认为线索可以在“高级经理问”中找到。 This person obviously stopped programming when he became a manager and then it took him/her several years to become a senior manager. 这个人在成为经理时显然已停止编程,然后他/她花了几年时间成为高级经理。 Never lost interest in programming, but never wrote a line since those days. 从来没有对编程感兴趣,但从那时起从未写过一条线。 So his reference is not "any decent compiler out there" as some answers mention, but "the compiler this person worked with 20-30 years ago". 所以他的参考文献不是“任何体面的编译器”,正如一些答案所提到的那样,而是“这个人在20 - 30年前工作的编译器”。

At that time, programmers spent a considerable percentage of their time trying out various methods for making their code faster and more efficient as CPU time of 'the central minicomputer' was so valueable. 那时,程序员花费了相当大的时间来尝试各种方法来使代码更快更有效,因为“中央小型机”的CPU时间非常有价值。 As did people writing compilers. 就像编写编译器的人一样。 I'm guessing that the one-and-only compiler his company made available at that time optimized on the basis of 'frequently encountered statements that can be optimized' and took a bit of a shortcut when encountering a while(1) and evaluated everything else, including a while(2). 我猜他的公司当时提供的唯一编译器是根据“经常遇到的可以优化的语句”进行优化的,并在遇到一段时间(1)时采取了一些快捷方式并评估了所有内容否则,包括一段时间(2)。 Having had such an experience could explain his position and his confidence in it. 有过这样的经历可以解释他的立场和对此的信心。

The best approach to get you hired is probably one that enables the senior manager to get carried away and lecture you 2-3 minutes on "the good old days of programming" before YOU smoothly lead him towards the next interview subject. 让你受雇的最佳方法可能就是让高级经理在你顺利领导他接下来的面试主题之前,在“编程的美好时光”上讲课2-3分钟。 (Good timing is important here - too fast and you're interrupting the story - too slow and you are labelled as somebody with insufficient focus). (好时机在这里很重要 - 太快了,你打断了故事 - 太慢了,你被贴上了一个焦点不足的人)。 Do tell him at the end of the interview that you'd be highly interested to learn more about this topic. 在面试结束时告诉他你对这个话题有更多的了解。

You should have asked him how did he reached to that conclusion. 你应该问他他是如何得出这个结论的。 Under any decent compiler out there, the two compile to the same asm instructions. 在任何体面的编译器下,两个编译为相同的asm指令。 So, he should have told you the compiler as well to start off. 所以,他应该告诉你编译器也要开始。 And even so, you would have to know the compiler and platform very well to even make a theoretical educated guess. 即使这样,你也必须非常了解编译器和平台,甚至做出理论上有根据的猜测。 And in the end, it doesn't really matter in practice, since there are other external factors like memory fragmentation or system load that will influence the loop more than this detail. 最后,它在实践中并不重要,因为还有其他外部因素,如内存碎片或系统负载,这将影响循环而不是这个细节。

For the sake of this question, I should that add I remember Doug Gwyn from C Committee writing that some early C compilers without the optimizer pass would generate a test in assembly for the while(1) (comparing to for(;;) which wouldn't have it). 为了这个问题,我应该补充一点,我记得来自C委员会的Doug Gwyn写道,没有优化器传递的早期C编译器会在while(1)汇编中生成一个测试(与for(;;)相比for(;;)没有它。

I would answer to the interviewer by giving this historical note and then say that even if I would be very surprised any compiler did this, a compiler could have: 我会通过给出这个历史记录回答面试官,然后说即使我对任何编译器都这样做感到非常惊讶,编译器也可以:

  • without optimizer pass the compiler generate a test for both while(1) and while(2) 没有优化器传递编译器生成while(1)while(2)
  • with optimizer pass the compiler is instructed to optimize (with an unconditional jump) all while(1) because they are considered as idiomatic. 使用优化器传递编译器被指示优化(使用无条件跳转)all while(1)因为它们被认为是惯用的。 This would leave the while(2) with a test and therefore makes a performance difference between the two. 这将使while(2)进行测试,从而在两者之间产生性能差异。

I would of course add to the interviewer that not considering while(1) and while(2) the same construct is a sign of low-quality optimization as these are equivalent constructs. 我当然会向面试官添加不考虑while(1)while(2)同一构造是低质量优化的标志,因为这些是等效构造。

Another take on such a question would be to see if you got courage to tell your manager that he/she is wrong! 对这样一个问题的另一个看法就是看你是否有勇气告诉你的经理他/她错了! And how softly you can communicate it. 你可以多么轻柔地沟通它。

My first instinct would have been to generate assembly output to show the manager that any decent compiler should take care of it, and if it's not doing so, you will submit the next patch for it :) 我的第一直觉是生成程序集输出以向管理员显示任何体面的编译器应该处理它,如果它没有这样做,你将为它提交下一个补丁:)

To see so many people delve into this problem, shows exactly why this could very well be a test to see how quickly you want to micro-optimize things. 为了看到这么多人深入研究这个问题,请说明为什么这很可能是一个测试,看看你想要多快地微观优化事物。

My answer would be; 我的回答是; it doesn't matter that much, I rather focus on the business problem which we are solving. 这并不重要,我更关注我们正在解决的业务问题。 After all, that's what I'm going to be paid for. 毕竟,这就是我要付出的代价。

Moreover, I would opt for while(1) {} because it is more common, and other teammates would not need to spend time to figure out why someone would go for a higher number than 1. 此外,我会选择while(1) {}因为它更常见,其他队友不需要花时间弄清楚为什么有人会选择高于1的数字。

Now go write some code. 现在去写一些代码。 ;-) ;-)

If you're that worried about optimisation, you should use 如果你担心优化,你应该使用

for (;;)

because that has no tests. 因为没有测试。 (cynic mode) (愤世嫉俗的模式)

It seems to me this is one of those behavioral interview questions masked as a technical question. 在我看来,这是一个被掩盖为技术问题的行为面试问题。 Some companies do this - they will ask a technical question that should be fairly easy for any competent programmer to answer, but when the interviewee gives the correct answer, the interviewer will tell them they are wrong. 有些公司会这样做 - 他们会问一个技术问题,任何有能力的程序员都应该很容易回答,但当受访者给出正确的答案时,面试官会告诉他们他们错了。

The company wants to see how you will react in this situation. 该公司希望了解您将如何应对这种情况。 Do you sit there quietly and don't push that your answer is correct, due to either self-doubt or fear of upsetting the interviewer? 你是否安静地坐在那里,不要因为自我怀疑或害怕面试官而烦恼你的答案是否正确? Or are you willing to challenge a person in authority who you know is wrong? 或者你是否愿意挑战一个你知道错误的权威人士? They want to see if you are willing to stand up for your convictions, and if you can do it in a tactful and respectful manner. 他们想看看你是否愿意坚持你的信念,如果你能够以一种委婉和尊重的方式做到这一点。

I used to program C and Assembly code back when this sort of nonsense might have made a difference. 当这种废话可能产生影响时,我曾经编程C和汇编代码。 When it did make a difference we wrote it in Assembly. 当它确实有所作为时,我们在大会上写了它。

If I were asked that question I would have repeated Donald Knuth's famous 1974 quote about premature optimization and walked if the interviewer didn't laugh and move on. 如果我被问到这个问题,我会重复唐纳德克努特1974年关于过早优化的着名言论,如果采访者不笑并继续前进,那就走了。

Maybe the interviewer posed such dumb question intentionally and wanted you to make 3 points: 也许面试官故意提出这样一个愚蠢的问题,并希望你提出3分:

  1. Basic reasoning. 基本推理。 Both loops are infinite, it's hard to talk about performance. 两个循环都是无限的,很难谈论性能。
  2. Knowledge about optimisation levels. 有关优化级别的知识。 He wanted to hear from you if you let the compiler do any optimisation for you, it would optimise the condition, especially if the block was not empty. 他想听听你是否让编译器为你做任何优化,它会优化条件,特别是如果块不为空。
  3. Knowledge about microprocessor architecture. 了解微处理器架构。 Most architectures have a special CPU instruction for comparision with 0 (while not necessarily faster). 大多数体系结构都有一个特殊的CPU指令用于与0进行比较(但不一定更快)。

Here's a problem: If you actually write a program and measure its speed, the speed of both loops could be different! 这是一个问题:如果您实际编写程序并测量其速度,则两个循环的速度可能会有所不同! For some reasonable comparison: 对于一些合理的比较:

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

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

with some code added that prints the time, some random effect like how the loop is positioned within one or two cache lines could make a difference. 添加一些代码打印时间,一些随机效果,如循环在一个或两个缓存行中的位置可能会有所不同。 One loop might by pure chance be completely within one cache line, or at the start of a cache line, or it might to straddle two cache lines. 一个循环可能完全在一个缓存行内,或者在缓存行的开头,或者它可能跨越两个缓存行。 And as a result, whatever the interviewer claims is fastest might actually be fastest - by coincidence. 因此,无论采访者声称最快,实际上可能是最快的 - 巧合。

Worst case scenario: An optimising compiler doesn't figure out what the loop does, but figures out that the values produced when the second loop is executed are the same ones as produced by the first one. 最糟糕的情况:优化编译器不会弄清楚循环的作用,但会发现第二个循环执行时产生的值与第一个循环产生的值相同。 And generate full code for the first loop, but not for the second. 并为第一个循环生成完整代码,但不为第二个循环生成完整代码。

They are both equal - the same. 它们都是平等的 - 相同。

According to the specifications anything that is not 0 is considered true, so even without any optimization, and a good compiler will not generate any code for while(1) or while(2). 根据规范,任何非0的都被认为是真的,所以即使没有任何优化,好的编译器也不会为while(1)或while(2)生成任何代码。 The compiler would generate a simple check for != 0 . 编译器会生成!= 0的简单检查。

Judging by the amount of time and effort people have spent testing, proving, and answering this very straight forward question Id say that both were made very slow by asking the question. 从人们花费大量时间和精力来测试,证明和回答这个非常直截了当的问题,Id说,通过提出问题,两者都变得非常缓慢。

And so to spend even more time on it ... 所以要花更多的时间在上面......

"while (2)" is ridiculous, because, “而(2)”是荒谬的,因为,

"while (1)", and "while (true)" are historically used to make an infinite loop which expects "break" to be called at some stage inside the loop based upon a condition that will certainly occur. “while(1)”和“while(true)”在历史上用于创建一个无限循环,该循环期望在循环内的某个阶段基于肯定会发生的条件调用“break”。

The "1" is simply there to always evaluate to true and therefore, to say "while (2)" is about as silly as saying "while (1 + 1 == 2)" which will also evaluate to true. “1”只是总是评估为真,因此,说“while(2)”与说“while(1 + 1 == 2)”一样愚蠢,这也将评估为真。

And if you want to be completely silly just use: - 如果你想完全愚蠢,只需使用: -

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

Id like to think your coder made a typo which did not effect the running of the code, but if he intentionally used the "2" just to be weird then sack him before he puts weird sh!t all through your code making it difficult to read and work with. 我想你的编码器做了一个不会影响代码运行的拼写错误,但是如果他故意使用“2”只是为了变得怪异,那么在他把所有代码变得难以置信之前给他带来奇怪的麻烦阅读和使用。

That depends on the compiler. 这取决于编译器。

If it optimizes the code, or if it evaluates 1 and 2 to true with the same number of instructions for a particular instruction set, the execution speed will be the same. 如果它优化代码,或者如果使用相同数量的指令对特定指令集计算1和2为真,则执行速度将相同。

In real cases it will always be equally fast, but it would be possible to imagine a particular compiler and a particular system when this would be evaluated differently. 在实际情况下,它总是同样快速,但是可以想象一个特定的编译器和一个特定的系统,当这将被不同地评估。

I mean: this is not really a language (C) related question. 我的意思是:这不是一个与语言(C)相关的问题。

Since people looking to answer this question want the fastest loop, I would have answered that both are equally compiling into the same assembly code, as stated in the other answers. 由于想要回答这个问题的人想要最快的循环,我会回答说两者同样编译成相同的汇编代码,如其他答案中所述。 Nevertheless you can suggest to the interviewer using 'loop unrolling'; 不过你可以使用'循环展开'向面试官建议; a do {} while loop instead of the while loop. do {} while循环而不是while循环。

Cautious: You need to ensure that the loop would at least always run once . 谨慎: 您需要确保循环至少始终运行一次

The loop should have a break condition inside. 循环内部应该有一个中断条件。

Also for that kind of loop I would personally prefer the use of do {} while(42) since any integer, except 0, would do the job. 同样对于那种循环,我个人更喜欢使用do {} while(42),因为除0之外的任何整数都可以完成这项工作。

The obvious answer is: as posted, both fragments would run an equally busy infinite loop, which makes the program infinitely slow . 显而易见的答案是:发布时,两个片段都会运行一个同样繁忙的无限循环,这会使程序无限

Although redefining C keywords as macros would technically have undefined behavior, it is the only way I can think of to make either code fragment fast at all: you can add this line above the 2 fragments: 虽然将C关键字重新定义为宏在技术上会有未定义的行为,但这是我能想到的任何一种代码片段都是快速的唯一方法:你可以在2个片段之上添加这一行:

#define while(x) sleep(x);

it will indeed make while(1) twice as fast (or half as slow) as while(2) . 它确实会使while(1)速度(或慢速的一半)( while(2)速度快一倍while(2)

The only reason I can think of why the while(2) would be any slower is: 我能想到为什么while(2)会变慢的唯一原因是:

  1. The code optimizes the loop to 代码优化循环

    cmp eax, 2

  2. When the subtract occurs you're essentially subtracting 当减法发生时,你基本上减去了

    a. 一个。 00000000 - 00000010 cmp eax, 2

    instead of 代替

    b. 00000000 - 00000001 cmp eax, 1

cmp only sets flags and does not set a result. cmp只设置标志而不设置结果。 So on the least significant bits we know if we need to borrow or not with b . 所以在最不重要的位上我们知道我们是否需要借用或不借用b Whereas with a you have to perform two subtractions before you get a borrow. 你必须执行两次减法你借了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM