我曾经听过一位老师丢弃它,此后一直困扰着我。假设我们要检查整数x
是否大于或等于0。有两种检查方法:
if (x > -1){
//do stuff
}
和
if (x >= 0){
//do stuff
}
据这个老师说>
会快一些>=
。在这种情况下,它是Java,但据他说,这也适用于C,c ++和其他语言。这句话有什么道理吗?
在现实世界中没有任何区别。
让我们看一下各种编译器为各种目标生成的代码。
-O2
针对GCC,/Ox
针对MSVC,-Oh
针对IAR)使用以下模块:
void my_puts(char const* s);
void cmp_gt(int x)
{
if (x > -1) {
my_puts(“non-negative”);
}
else {
my_puts(“negative”);
}
}
void cmp_gte(int x)
{
if (x >= 0) {
my_puts(“non-negative”);
}
else {
my_puts(“negative”);
}
}
这是它们每个人为比较操作产生的结果:
针对ARM的MSVC 11:
// if (x > -1) {...
00000 |cmp_gt| PROC
00000 f1b0 3fff cmp r0,#0xFFFFFFFF
00004 dd05 ble |$LN2@cmp_gt|
// if (x >= 0) {...
00024 |cmp_gte| PROC
00024 2800 cmp r0,#0
00026 db05 blt |$LN2@cmp_gte|
针对x64的MSVC 11:
// if (x > -1) {...
cmp_gt PROC
00000 83 f9 ff cmp ecx, -1
00003 48 8d 0d 00 00 // speculative load of argument to my_puts()
00 00 lea rcx, OFFSET FLAT:$SG1359
0000a 7f 07 jg SHORT $LN5@cmp_gt
// if (x >= 0) {...
cmp_gte PROC
00000 85 c9 test ecx, ecx
00002 48 8d 0d 00 00 // speculative load of argument to my_puts()
00 00 lea rcx, OFFSET FLAT:$SG1367
00009 79 07 jns SHORT $LN5@cmp_gte
针对x86的MSVC 11:
// if (x > -1) {...
_cmp_gt PROC
00000 83 7c 24 04 ff cmp DWORD PTR _x$[esp-4], -1
00005 7e 0d jle SHORT $LN2@cmp_gt
// if (x >= 0) {...
_cmp_gte PROC
00000 83 7c 24 04 00 cmp DWORD PTR _x$[esp-4], 0
00005 7c 0d jl SHORT $LN2@cmp_gte
针对x64的GCC 4.6.1
// if (x > -1) {...
cmp_gt:
.seh_endprologue
test ecx, ecx
js .L2
// if (x >= 0) {...
cmp_gte:
.seh_endprologue
test ecx, ecx
js .L5
针对x86的GCC 4.6.1:
// if (x > -1) {...
_cmp_gt:
mov eax, DWORD PTR [esp+4]
test eax, eax
js L2
// if (x >= 0) {...
_cmp_gte:
mov edx, DWORD PTR [esp+4]
test edx, edx
js L5
针对ARM的GCC 4.4.1:
// if (x > -1) {...
cmp_gt:
.fnstart
.LFB0:
cmp r0, #0
blt .L8
// if (x >= 0) {...
cmp_gte:
.fnstart
.LFB1:
cmp r0, #0
blt .L2
针对ARM Cortex-M3的IAR 5.20:
// if (x > -1) {...
cmp_gt:
80B5 PUSH {R7,LR}
.... LDR.N R1,??DataTable1 ;; `?<Constant "non-negative">`
0028 CMP R0,#+0
01D4 BMI.N ??cmp_gt_0
// if (x >= 0) {...
cmp_gte:
80B5 PUSH {R7,LR}
.... LDR.N R1,??DataTable1 ;; `?<Constant "non-negative">`
0028 CMP R0,#+0
01D4 BMI.N ??cmp_gte_0
如果您仍然与我在一起,则这里是评估(x > -1)
与(x >= 0)
显示之间任何注释的区别:
cmp r0,#0xFFFFFFFF
为(x > -1)
VS cmp r0,#0
的(x >= 0)
。第一条指令的操作码长两个字节。我想这可能会增加一些时间,所以我们称此为(x >= 0)
cmp ecx, -1
为(x > -1)
VS test ecx, ecx
的(x >= 0)
。第一条指令的操作码长一个字节。我想这可能会增加一些时间,所以我们称此为(x >= 0)
请注意,GCC和IAR为两种比较生成了相同的机器代码(可能使用了哪个寄存器除外)。因此,根据这项调查,似乎(x >= 0)
“变快”的可能性很小。但是,最小操作码字节编码可能具有的任何优势(我强调) 可能 会被其他因素完全掩盖。
如果您发现Java或C#的混合输出有什么不同,我会感到惊讶。我怀疑即使对于8位AVR这样的很小的目标,您也会发现音符有什么不同。
简而言之,不必担心这种微优化。我想我在这里写的文章已经花了更多的时间,而我一生中所有执行它们的CPU上所积累的这些表达式的性能的任何差异所花费的时间。如果您有能力测量性能差异,请将您的精力投入到更重要的事情上,例如研究亚原子粒子的行为或其他事情。
根据这位老师的说法,会比稍微快一点。在本例中,它是Java,但据他说,这也适用于C、C++和其他语言。这种说法有道理吗?
问题内容: 如果我使用Javac打开调试信息的生成,则类文件将增加20-25%。这对运行Java程序有任何性能影响吗?如果是,则在哪些条件下以及在多少条件下。我希望对加载类有一点影响,因为文件较大,但这应该很小。 问题答案: 用任何语言,调试信息都是元信息。它的性质增加了目标文件的大小,从而增加了加载时间。在调试器外部执行期间,实际上完全忽略了此信息。如JVM规范中所述(尽管不清楚),调试信息存储
问题内容: 并且似乎返回相同的结果。它们之间有什么性能差异,为什么? 问题答案: deque.popleft()比list.pop(0)更快,这是因为deque已被优化以在O(1)中执行popleft(),而list.pop(0)需要O(n)(请参阅deque对象) 。 _collectionsmodule.c中用于deque的注释和代码以及listobject.c中用于list的注释和代码提供了
问题内容: 以下两个循环之间的性能差异(如果有)是什么? 和 问题答案: 版本1.5中引入的for-each循环通过完全隐藏迭代器或index变量,消除了混乱和出错的机会。结果成语同样适用于集合和数组: 当你看到冒号(:)时,将其读为“ in”。因此,上面的循环读为“对于元素中的每个元素e”。请注意,即使对于数组,使用for-each循环也不会降低性能。实际上,在某些情况下,它可能只比普通的for
说到“性能差异”,到目前为止,我还没有读到什么可靠的东西。 基于其官方文档,作为bool查询中使用的筛选器 子句(查询)必须出现在匹配的文档中。但是,与must不同的是,查询的分数将被忽略。筛选子句在筛选上下文中执行,这意味着计分被忽略,子句被考虑用于缓存。 至于常数分数查询 筛选查询不计算相关性得分。为了提高性能,Elasticsearch会自动缓存经常使用的筛选器查询。 QAs我刚刚读到:El
在循环中,我们不断终止条件,并在每一次传递中检查这些条件。 我见过2种检查方法 1.或