gpt4 book ai didi

java - 哪个迭代数组的习惯用法最有效?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:08:32 24 4
gpt4 key购买 nike

Java 5 为我们提供了 for-each 循环,应尽可能使用它。

但是如果你需要在 block 中使用数组的索引,最有效的习惯用法是什么?

// Option (1)
for (int i = array.length - 1; i >= 0; i--) {
// Code.
}

// Option (2)
for (int i = 0; i < array.length; i++) {
// Code.
}

// Option (3)
for (int i = 0, n = array.length; i < n; i++) {
// Code.
}

(显然,这在大多数程序中不会产生很大的性能差异,但请原谅我。):-)

  1. 向后循环并且很丑陋。甚至缓存不友好?还是现代处理器可以检测内存中的后退?

  2. 更短,我可以看到 JIT 编译器如何确定 array 永远不会改变,因此 length 是常量,所以它基本上可以用 ( 3).但它这样做了吗? (假设 JVM 是 Oracle 的 Hotspot/Java 7。)

  3. 由 Joshua Bloch 在 Effective Java 的第 45 项中建议作为最快的选择,如果它是一些 Collection.size() 这是上限。但它也适用于数组吗?从字节码(见下文)我可以看到每个周期(预优化)保存一条 arraylength 指令。

This question关于 Dalvik 虚拟机中的 for 循环,将 (1)-(3) 列为最快到最慢。然而,这些信息是 2008 年的,今天的 Dalvik 已经成熟得多,所以我不认为情况仍然如此。

看上面例子生成的字节码,有明显的区别:

Compiled from "ForLoops.java"
public class ForLoops extends java.lang.Object{
static int[] array;

public ForLoops();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: return

public static void forLoop1();
Code:
0: getstatic #17; //Field array:[I
3: arraylength
4: iconst_1
5: isub
6: istore_0
7: goto 13
10: iinc 0, -1
13: iload_0
14: ifge 10
17: return

public static void forLoop2();
Code:
0: iconst_0
1: istore_0
2: goto 8
5: iinc 0, 1
8: iload_0
9: getstatic #17; //Field array:[I
12: arraylength
13: if_icmplt 5
16: return

public static void forLoop3();
Code:
0: iconst_0
1: istore_0
2: getstatic #17; //Field array:[I
5: arraylength
6: istore_1
7: goto 13
10: iinc 0, 1
13: iload_0
14: iload_1
15: if_icmplt 10
18: return

}

最佳答案

您可以轻松地自己测试一下;如果你这样做,你应该看看 these tips about performance testing来自 HotSpot 创作者自己。 This answer也可能有用。如果您决定测试这些实现,请告诉我们您的发现!

不过,总的来说,你不应该太担心这些事情。相反,专注于编写可读代码并完成任务。大多数时候,您会发现您的代码运行速度足够快,无需任何“技巧”。现代硬件非常快,而且 JIT 也非常好。

如果您确实发现您的代码运行速度太慢,请先分析,然后再优化。其他任何事情都为时过早。请记住,来自一个比我们任何人都聪明的人:

"Premature optimization is the root of all evil." -- Donald Knuth

编辑:从“我应该如何编写代码?”的角度来看,您似乎对此不太感兴趣。更就思想实验而言,我期望所有这些选项以或多或少相同的速度运行。

这些循环中没有一个可能会调整分支预测器(无论如何对于合理大小的数组)。我期望底层 JIT 将任何重复出现的数组长度引用从 (2) 样式转换为 (3) 样式。在所有条件相同的情况下,(1) 的缓存性能并不比 (2) 或 (3) 差,仅仅是因为它向后运行;对于给定的数组,相同的缓存行将被加载和命中(或未命中)的频率相同。

当然,我的期望是无关紧要的。唯一知道的方法就是测试!但是,在测试时,请记住 writing good microbenchmarks is hard .

关于java - 哪个迭代数组的习惯用法最有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17515720/

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