gpt4 book ai didi

java - 为什么处理排序数组比未排序数组*慢*? (Java 的 ArrayList.indexOf)

转载 作者:IT老高 更新时间:2023-10-28 11:43:51 26 4
gpt4 key购买 nike

标题引用Why is it faster to process a sorted array than an unsorted array?

这也是分支预测效果吗?注意:这里对排序数组的处理是更慢!!

考虑以下代码:

private static final int LIST_LENGTH = 1000 * 1000;
private static final long SLOW_ITERATION_MILLIS = 1000L * 10L;

@Test
public void testBinarySearch() {
Random r = new Random(0);
List<Double> list = new ArrayList<>(LIST_LENGTH);
for (int i = 0; i < LIST_LENGTH; i++) {
list.add(r.nextDouble());
}
//Collections.sort(list);
// remove possible artifacts due to the sorting call
// and rebuild the list from scratch:
list = new ArrayList<>(list);

int nIterations = 0;
long startTime = System.currentTimeMillis();
do {
int index = r.nextInt(LIST_LENGTH);
assertEquals(index, list.indexOf(list.get(index)));
nIterations++;
} while (System.currentTimeMillis() < startTime + SLOW_ITERATION_MILLIS);
long duration = System.currentTimeMillis() - startTime;
double slowFindsPerSec = (double) nIterations / duration * 1000;
System.out.println(slowFindsPerSec);

...
}

这会在我的机器上打印出大约 720 的值。

现在,如果我激活集合排序调用,该值会下降到 142。为什么?!?

结果决定性的,如果我增加迭代次数/时间,它们不会改变。

Java 版本为 1.8.0_71(Oracle VM,64 位),在 Windows 10 下运行,在 Eclipse Mars 中进行 JUnit 测试。

更新

似乎与连续内存访问有关(按顺序访问的双对象与按随机顺序访问)。对于大约 10k 或更少的数组长度,效果开始消失。

感谢 assylias 提供 the results :

/**
* Benchmark Mode Cnt Score Error Units
* SO35018999.shuffled avgt 10 8.895 ± 1.534 ms/op
* SO35018999.sorted avgt 10 8.093 ± 3.093 ms/op
* SO35018999.sorted_contiguous avgt 10 1.665 ± 0.397 ms/op
* SO35018999.unsorted avgt 10 2.700 ± 0.302 ms/op
*/

最佳答案

看起来像缓存/预取的效果。

线索是您比较 double (对象),而不是 double (基元)。当您在一个线程中分配对象时,它们通常在内存中按顺序分配。所以当 indexOf 扫描一个列表时,它会遍历顺序的内存地址。这对于 CPU 缓存预取启发式很有用。

但是在你对列表进行排序之后,你仍然需要平均执行相同数量的内存查找,但这次内存访问将是随机顺序的。

更新

Here is the benchmark 证明分配对象的顺序很重要。

Benchmark            (generator)  (length)  (postprocess)  Mode  Cnt  Score   Error  Units
ListIndexOf.indexOf random 1000000 none avgt 10 1,243 ± 0,031 ms/op
ListIndexOf.indexOf random 1000000 sort avgt 10 6,496 ± 0,456 ms/op
ListIndexOf.indexOf random 1000000 shuffle avgt 10 6,485 ± 0,412 ms/op
ListIndexOf.indexOf sequential 1000000 none avgt 10 1,249 ± 0,053 ms/op
ListIndexOf.indexOf sequential 1000000 sort avgt 10 1,247 ± 0,037 ms/op
ListIndexOf.indexOf sequential 1000000 shuffle avgt 10 6,579 ± 0,448 ms/op

关于java - 为什么处理排序数组比未排序数组*慢*? (Java 的 ArrayList.indexOf),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35018999/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com