java 为什么处理排序数组比处理未排序数组更快?
注:本文转自《白煮蛋的博客》
数据排序后性能显着提高的原因是分支预测惩罚被删除,正如Mysticial 的回答中所解释的那样。
现在,如果我们看一下代码
if (data[c] >= 128)
sum += data[c];
我们可以发现这个特定if... else...
分支的含义是在满足条件时添加一些东西。这种类型的分支可以很容易地转换为条件移动语句,该语句将在系统中编译为条件移动指令:cmovl
,x86
。分支和潜在的分支预测惩罚被移除。
C
因此,在C++
中,将直接编译(没有任何优化)到条件移动指令中的语句x86
是三元运算符... ? ... : ...
。所以我们把上面的语句改写成等价的:
sum += data[c] >=128 ? data[c] : 0;
在保持可读性的同时,我们可以检查加速因子。
在 Intel Core i7 -2600K @ 3.4 GHz 和 Visual Studio 2010 发布模式上,基准测试为:
x86
设想 | 时间(秒) |
---|---|
分支 - 随机数据 | 8.885 |
分支 - 排序数据 | 1.528 |
无分支 - 随机数据 | 3.716 |
无分支 - 排序数据 | 3.71 |
x64
设想 | 时间(秒) |
---|---|
分支 - 随机数据 | 11.302 |
分支 - 排序数据 | 1.830 |
无分支 - 随机数据 | 2.736 |
无分支 - 排序数据 | 2.737 |
结果在多次测试中是稳健的。当分支结果不可预测时,我们得到了很大的加速,但当它是可预测的时,我们会受到一点影响。事实上,当使用条件移动时,无论数据模式如何,性能都是相同的。
x86
现在让我们通过调查它们生成的程序集来更仔细地观察。为简单起见,我们使用两个函数max1
和max2
。
max1
使用条件分支if... else ...
:
int max1(int a, int b) {
if (a > b)
return a;
else
return b;
}
max2
使用三元运算符... ? ... : ...
:
int max2(int a, int b) {
return a > b ? a : b;
}
在 x86-64 机器上,GCC -S
生成下面的程序集。
:max1
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
cmpl -8(%rbp), %eax
jle .L2
movl -4(%rbp), %eax
movl %eax, -12(%rbp)
jmp .L4
.L2:
movl -8(%rbp), %eax
movl %eax, -12(%rbp)
.L4:
movl -12(%rbp), %eax
leave
ret
:max2
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
cmpl %eax, -8(%rbp)
cmovge -8(%rbp), %eax
leave
ret
max2
由于使用指令,使用更少的代码cmovge
。但真正的收获是max2
不涉及分支跳转,jmp
如果预测结果不正确,这将产生显着的性能损失。
那么为什么有条件的移动表现更好呢?
在典型的x86
处理器中,一条指令的执行分为几个阶段。粗略地说,我们有不同的硬件来处理不同的阶段。所以我们不必等待一条指令完成来开始新的指令。这称为流水线。
在分支情况下,后面的指令是由前面的指令决定的,所以我们不能进行流水线操作。我们必须等待或预测。
在条件移动情况下,执行条件移动指令分为几个阶段,但前面的阶段喜欢Fetch
并且Decode
不依赖于前一条指令的结果;只有后期需要结果。因此,我们等待一条指令执行时间的一小部分。这就是为什么当预测很容易时条件移动版本比分支慢的原因。
《Computer Systems: A Programmer's Perspective》一书,第二版详细解释了这一点。您可以查看第 3.6.6 节中的条件移动指令、整个第 4 章中的处理器架构以及第 5.11.2 节中有关分支预测和错误预测惩罚的特殊处理。
有时,一些现代编译器可以将我们的代码优化为具有更好性能的汇编,有时一些编译器不能(有问题的代码使用 Visual Studio 的本机编译器)。当场景变得如此复杂以至于编译器无法自动优化它们时,了解分支和条件移动之间的性能差异可以帮助我们编写性能更好的代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具