这是一位高级经理问的面试问题。
哪个更快?
while(1) {
// Some code
}
while(2) {
//Some code
}
我说过,这两者具有相同的执行速度,因为while
内部的表达式最终应计算为true
或false
。在这种情况下,两者的计算结果都为true
,while
条件中没有额外的条件指令。因此,两者的执行速度相同,我更喜欢while(1)。
但面试官自信地说:“检查一下你的基础,while(1)
比while(2)
要快。”(他不是在考验我的信心)
这是真的吗?
两个循环都是无限的,但是我们可以看到哪个循环每次迭代需要更多的指令/资源。
使用gcc,我编译了以下两个程序,以便在不同的优化级别上进行组装:
int main(void) {
while(1) {}
return 0;
}
int main(void) {
while(2) {}
return 0;
}
即使没有优化(-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"
使用-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"
使用-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"
.L2:
jmp .L2
.seh_endproc
.ident "GCC: (tdm64-2) 4.8.1"
.L2:
jmp .L2
我不能很好地读取assembly,但这显然是一个无条件循环。jmp
指令无条件地将程序重置回.l2
标签,甚至不需要将值与true进行比较,并且当然会立即再次这样做,直到程序以某种方式结束。这直接对应于C/C++代码:
L2:
goto L2;
编辑:
非常有趣的是,即使没有优化,以下循环都在汇编中生成了完全相同的输出(无条件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) {}
#include<math.h>
while(sqrt(7)) {}
while(hypot(3,4)) {}
用户定义函数会让事情变得更有趣:
int x(void) {
return 1;
}
while(x()) {}
#include<math.h>
double x(void) {
return sqrt(7);
}
while(x()) {}
在-o0
处,这两个示例实际上调用x
并为每个迭代执行一个比较。
第一个示例(返回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"
.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"
在GCC下,不同的循环被编译成相同的程序集。编译器计算常量值,而不需要执行任何实际比较。
这个故事的寓意是:
问题内容: 如果您的目标是测试MySQL列中是否存在字符串(类型为’varchar’,’text’,’blob’等),那么以下哪一项是更快/更有效/更好地使用,为什么? 或者,还有其他方法可以胜任这些方法吗? 与 问题答案: 正如kibibu在上述评论中指出的,FULLTEXT搜索绝对会更快。 但是 : 在我的测试中,它们的表现完全相同。它们都不区分大小写,并且通常会执行全表扫描,这在处理高性能M
1. while语句 在第 3 节 “递归”中,我们介绍了用递归求n!的方法,其实每次递归调用都在重复做同样一件事,就是把n乘到(n-1)!上然后把结果返回。虽说是重复,但每次做都稍微有一点区别(n的值不一样),这种每次都有一点区别的重复工作称为迭代(Iteration)。我们使用计算机的主要目的之一就是让它做重复迭代的工作,因为把一件工作重复做成千上万次而不出错正是计算机最擅长的,也是人类最不擅
终于,来到了shell十三问的最后一问了... 长长吐一口气~~~~ 最后要介绍的是shell script设计中常见的循环(loop). 所谓的loop就是script中的一段在一定条件下反复执行的代码。 bash shell中常用的loop有如下三种: for while until 1. for loop for loop 是从一个清单列表中读进变量的值, 并依次的循环执行do到done之间
我的程序中有两个while循环。第一个是针对游戏菜单的,第二个是针对实际游戏的。如果“Gameover-Event”发生,我想返回菜单。我不知道该怎么做。
问题内容: 可以说我有一个图,想看看是否。哪个实施速度更快,为什么? 要么 显然,这过于简单了,但可以想象该图变得非常密集。 问题答案: 集合中的成员资格测试要快得多,尤其是对于大型集合。这是因为该集合使用哈希函数来映射到存储桶。由于Python实现会自动调整该哈希表的大小,因此无论集合的大小如何,速度都可以保持恒定()(假设哈希函数足够好)。 相反,要评估对象是否为列表的成员,Python必须比
问题内容: 我知道我们可以进行相关的子查询并加入。但是哪一个更快?有黄金法则还是我必须同时衡量这两者? 问题答案: 首先,相关子查询实际上是联接的一种。关于哪一个产生最佳执行计划没有黄金法则。如果您对性能感兴趣,则需要尝试不同的表格以查看最有效的方法。或者,至少,看看执行该决定的执行计划。 通常,出于两个原因,我倾向于避免关联子查询。首先,几乎总是可以在没有相关性的情况下编写它们。其次,许多查询引