为什么处理有序的数组比无序的数组更快

考虑一个铁路枢纽:

显示铁路路口的图像 Mecanismo 提供的图像,来自 Wikimedia Commons。在 CC-By-SA 3.0 许可下使用。

现在为了争论,假设这是在 1800 年代——在远距离或无线电通信之前。

你是一个路口的盲人操作员,你听到火车来了。你不知道它应该走哪条路。你停下火车问司机他们想要哪个方向。然后你适当地设置开关。

火车很重并且有很大的惯性,所以它们需要很长时间才能启动和减速。

有没有更好的办法?你猜火车会开往哪个方向!

如果你猜对了,它会继续。
如果你猜错了,船长会停下来,后退,然后对你大喊大叫来拨动开关。然后它可以重新启动另一条路径。
如果你每次都猜对了,火车就永远不用停下来。
如果您经常猜错,火车将花费大量时间停止、倒车和重新启动。

考虑一个 if 语句:在处理器级别,它是一个分支指令:

包含 if 语句的已编译代码的屏幕截图

你是一个处理器,你看到一个分支。你不知道它会朝哪个方向发展。你做什么工作?您停止执行并等待前面的指令完成。然后你继续沿着正确的路径前进。

现代处理器很复杂并且有很长的流水线。这意味着他们需要永远“热身”和“减速”。

有没有更好的办法?你猜这个分支会往哪个方向走!

如果你猜对了,你继续执行。
如果你猜错了,你需要刷新管道并回滚到分支。然后,您可以重新启动另一条路径。
如果你每次都猜对了,执行将永远不会停止。
如果您经常猜错,您会花费大量时间停止、回滚和重新启动。

这是分支预测。我承认这不是最好的类比,因为火车只能用旗帜指示方向。但是在计算机中,处理器直到最后一刻才知道分支将走向哪个方向。

您将如何策略性地猜测以最小化火车必须倒车并沿另一条路径行驶的次数?你看看过去的历史!如果火车 99% 的时间都是左转,那么你猜是左转。如果它交替,那么你交替你的猜测。如果它每 3 次去一个方向,你猜同样…

换句话说,您尝试识别一种模式并遵循它。这或多或少是分支预测器的工作方式。

大多数应用程序都有良好的分支。因此,现代分支预测器通常会达到 >90% 的命中率。但是当面对无法识别的模式的不可预测的分支时,分支预测器实际上是无用的。

进一步阅读:维基百科上的“分支预测器”文章。

正如上面所暗示的,罪魁祸首是这个 if 语句:
如果(数据 [c] >= 128)
总和 += 数据[c];
注意数据均匀分布在 0 到 255 之间。当对数据进行排序时,大约前一半的迭代不会进入 if 语句。之后,它们都将进入 if 语句。

这对分支预测器非常友好,因为分支连续多次朝同一个方向移动。即使是一个简单的饱和计数器也能正确预测分支,除了它切换方向后的几次迭代。

快速可视化:

T = 采用的分支
N = 未采用分支

数据[] = 0, 1, 2, 3, 4, … 126, 127, 128, 129, 130, … 250, 251, 252, …
分支 = N N N N N … N N T T T … T T T …

   = NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT(易于预测)

但是,当数据完全随机时,分支预测器就变得毫无用处,因为它无法预测随机数据。因此可能会有大约 50% 的错误预测(不比随机猜测好)。

数据[] = 226, 185, 125, 158, 198, 144, 217, 79, 202, 118, 14, 150, 177, 182, …
分支 = T, T, N, T, T, T, T, N, T, N, N, T, T, T …

   = TTNTTTTNTNNTTT ...(完全随机 - 无法预测)

可以做什么?

如果编译器无法将分支优化为条件移动,如果您愿意牺牲可读性来换取性能,您可以尝试一些技巧。

代替:

如果(数据 [c] >= 128)
总和 += 数据[c];
和:

int t = (data[c] - 128) >> 31;
总和 += ~t & 数据[c];
这消除了分支并用一些按位操作替换它。

(请注意,这个 hack 并不严格等同于原始 if 语句。但在这种情况下,它对 data[] 的所有输入值都有效。)

基准测试:Core i7 920 @ 3.5 GHz

C++ - Visual Studio 2010 - x64 版本

场景时间(秒)
分支 - 随机数据 11.777
分支 - 排序数据 2.352
无分支 - 随机数据 2.564
无分支 - 排序数据 2.587
Java - NetBeans 7.1.1 JDK 7 - x64

场景时间(秒)
分支 - 随机数据 10.93293813
分支 - 排序数据 5.643797077
无分支 - 随机数据 3.113581453

https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array/11227902#11227902

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值