增强的循环性能比传统的索引查找更差?

jkr*_*ill 10 java performance

我刚刚看到这个看似无害的评论,对ArrayList和原始String数组进行基准测试.它来自几年前,但OP写道

我注意到使用String s:stringsList比使用旧式for循环访问列表慢约50%.去搞清楚...

没有人在原帖中评论它,测试看起来有点可疑(太短不准确),但是当我读到它时,我差点从椅子上掉下来.我从来没有对一个"传统"的循环增强循环进行基准测试,但我目前正在开发一个项目,它使用增强循环对ArrayList实例进行数亿次迭代,所以这是我关注的问题.

我打算做一些基准测试并在此发表我的发现,但这显然是我的一个大问题.我可以在网上找到关于相对性能的宝贵的小信息,除了一些随便提到的ArrayLists的增强循环在Android下运行速度慢得多.

有没有人经历过这个?这种性能差距是否仍然存在?我会在这里发布我的发现,但读到它时非常惊讶.我怀疑如果这个性能差距确实存在,它已经在更现代的VM中得到修复,但我想我现在必须做一些测试并确认.

更新:我对我的代码进行了一些更改,但是已经怀疑其他人已经指出的内容:确保增强的for循环速度较慢,但​​是在非常简单的紧密循环之外,成本应该是成本的一​​小部分.循环的逻辑.就我而言,即使我使用增强型循环迭代非常大的字符串列表,我在循环中的逻辑也足够复杂,甚至在切换到基于索引的循环之后我甚至无法测量差异.

TL; DR:增强循环确实比传统的基于索引的循环慢于arraylist; 但对于大多数应用来说,差异应该可以忽略不计.

Pet*_*rey 9

您遇到的问题是使用Iterator比使用直接查找要慢.在我的机器上,每次迭代的差异大约为0.13 ns.使用数组代替每次迭代节省大约0.15 ns.在99%的情况下,这应该是微不足道的.

public static void main(String... args) {
    int testLength = 100 * 1000 * 1000;
    String[] stringArray = new String[testLength];
    Arrays.fill(stringArray, "a");
    List<String> stringList = new ArrayList<String>(Arrays.asList(stringArray));
    {
        long start = System.nanoTime();
        long total = 0;
        for (String str : stringArray) {
            total += str.length();
        }
        System.out.printf("The for each Array loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
    {
        long start = System.nanoTime();
        long total = 0;
        for (int i = 0, stringListSize = stringList.size(); i < stringListSize; i++) {
            String str = stringList.get(i);
            total += str.length();
        }
        System.out.printf("The for/get List loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
    {
        long start = System.nanoTime();
        long total = 0;
        for (String str : stringList) {
            total += str.length();
        }
        System.out.printf("The for each List loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
}
Run Code Online (Sandbox Code Playgroud)

当以10亿个条目运行条目打印时(使用Java 6更新26)

The for each Array loop time was 0.76 ns total=1000000000
The for/get List loop time was 0.91 ns total=1000000000
The for each List loop time was 1.04 ns total=1000000000
Run Code Online (Sandbox Code Playgroud)

以10亿个条目运行时打印条目(使用OpenJDK 7)

The for each Array loop time was 0.76 ns total=1000000000
The for/get List loop time was 0.91 ns total=1000000000
The for each List loop time was 1.04 ns total=1000000000
Run Code Online (Sandbox Code Playgroud)

即完全相同.;)


jmg*_*jmg 5

每个声称X在JVM上比Y慢,并没有解决本文中提到的所有问题,而它的第二部分则传播了对典型JVM性能的担忧和谎言.这适用于原始问题所引用的评论以及GravityBringer的答案.我很抱歉这么粗鲁,但除非你使用适当的微基准测试技术,否则你的基准测试会产生非常严重偏斜的随机数.

如果您对更多解释感兴趣,请告诉我.虽然这些都在我提到的文章中.