增强的循环性能比传统的索引查找更差? [英] Enhanced for loop performance worse than traditional indexed lookup?

查看:114
本文介绍了增强的循环性能比传统的索引查找更差?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I just came across this seemingly innocuous comment, benchmarking ArrayList vs a raw String array. It's from a couple years ago, but the OP writes


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

I did notice that using for String s: stringsList was about 50% slower than using an old-style for-loop to access the list. Go figure...

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

Nobody commented on it in the original post, and the test seemed a little dubious (too short to be accurate), but I nearly fell out of my chair when I read it. I've never benchmarked an enhanced loop against a "traditional" one, but I'm currently working on a project that does hundreds of millions of iterations over ArrayList instances using enhanced loops so this is a concern to me.

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

I'm going to do some benchmarking and post my findings here, but this is obviously a big concern to me. I could find precious little info online about relative performance, except for a couple offhand mentions that enhanced loops for ArrayLists do run a lot slower under Android.

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

Has anybody experienced this? Does such a performance gap still exist? I'll post my findings here, but was very surprised to read it. I suspect that if this performance gap did exist, it has been fixed in more modern VM's, but I guess now I'll have to do some testing and confirm.

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

Update: I made some changes to my code, but was already suspecting what others here have already pointed out: sure the enhanced for loop is slower, but outside of very trivial tight loops, the cost should be a miniscule fraction of the cost of the logic of the loop. In my case, even though I'm iterating over very large lists of strings using enhanced loops, my logic inside the loop is complex enough that I couldn't even measure a difference after switching to index-based loops.

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

TL;DR: enhanced loops are indeed slower than a traditional index-based loop over an arraylist; but for most applications the difference should be negligible.

推荐答案

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

The problem you have is that using an Iterator will be slower than using a direct lookup. On my machine the difference is about 0.13 ns per iteration. Using an array instead saves about 0.15 ns per iteration. This should be trivial in 99% of situations.

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);
    }
}

以十亿条目运行条目打印(使用Java 6更新26。)

When run with one billion entries entries prints (using Java 6 update 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

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

When run with one billion entries entries prints (using 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

ie完全相同的。 ;)

i.e. exactly the same. ;)

这篇关于增强的循环性能比传统的索引查找更差?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆