原始数组的现代 for 循环
原始数组上的 for 循环之间有性能差异吗?
假设:
double[] doubleArray = new double[300000];
for (double var: doubleArray)
someComplexCalculation(var);
或 :
for ( int i = 0, y = doubleArray.length; i < y; i++)
someComplexCalculation(doubleArray[i]);
测试结果
我实际上对其进行了分析:
Total timeused for modern loop= 13269ms
Total timeused for old loop = 15370ms
所以现代循环实际上运行得更快,至少在我的 Mac OSX JVM 1.5 上是这样。
Is there any performance difference between the for loops on a primitive array?
Assume:
double[] doubleArray = new double[300000];
for (double var: doubleArray)
someComplexCalculation(var);
or :
for ( int i = 0, y = doubleArray.length; i < y; i++)
someComplexCalculation(doubleArray[i]);
Test result
I actually profiled it:
Total timeused for modern loop= 13269ms
Total timeused for old loop = 15370ms
So the modern loop actually runs faster, at least on my Mac OSX JVM 1.5.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您手写的“旧”形式执行的指令更少,并且可能更快,尽管您必须在给定的 JIT 编译器下对其进行分析才能确定。 “新”形式肯定不更快。
如果您查看反汇编代码(由 Sun 的 JDK 1.5 编译),您会发现“new”形式相当于以下代码:
因此,您可以看到使用了更多的局部变量。 第 1 行将
doubleArray
分配给tmp
是“额外”的,但它不会出现在循环中,并且可能无法测量。 第 3 行对 var 的赋值也是额外的。 如有性能差异,责任自负。第 1 行可能看起来没有必要,但如果在进入循环之前通过方法计算数组,则它是缓存结果的样板。
也就是说,我会使用新形式,除非您需要对索引变量执行某些操作。 任何性能差异都可能被 JIT 编译器在运行时优化掉,并且新的形式更加清晰。 如果您继续“手动”执行此操作,您可能会错过未来的优化。 一般来说,一个好的编译器可以很好地优化“愚蠢”的代码,但会在“智能”的代码上失败。
Your hand-written, "old" form executes fewer instructions, and may be faster, although you'd have to profile it under a given JIT compiler to know for sure. The "new" form is definitely not faster.
If you look at the disassembled code (compiled by Sun's JDK 1.5), you'll see that the "new" form is equivalent to the following code:
So, you can see that more local variables are used. The assignment of
doubleArray
totmp
at line 1 is "extra", but it doesn't occur in the loop, and probably can't be measured. The assignment tovar
at line 3 is also extra. If there is a difference in performance, this would be responsible.Line 1 might seem unnecessary, but it's boilerplate to cache the result if the array is computed by a method before entering the loop.
That said, I would use the new form, unless you need to do something with the index variable. Any performance difference is likely to be optimized away by the JIT compiler at runtime, and the new form is more clear. If you continue to do it "by hand", you may miss out on future optimizations. Generally, a good compiler can optimize "stupid" code well, but stumbles on "smart" code.
我的意见是你不知道也不应该猜测。 如今试图智胜编译器是徒劳的。
有时人们学习的“模式”似乎可以优化某些操作,但在 Java 的下一个版本中,这些模式实际上更慢。
始终尽可能清晰地编写它,并且不要担心优化,直到您实际上掌握了一些用户规范并且无法满足某些要求,即使如此,也要非常小心地在测试之前和之后运行,以确保您的“修复”实际上改进了它足以满足该要求。
编译器可以做一些令人惊奇的事情,这些事情真的会让你大吃一惊,即使你做了一些在某个大范围内迭代的测试,如果你有一个较小的范围或改变循环内发生的事情,它的表现也可能完全不同。
及时编译意味着它偶尔可以超越 C,并且在某些情况下它没有理由不能超越静态汇编语言(汇编无法事先确定不需要调用,Java 有时可以做到这一点。
总而言之:代码的最大价值就是将其编写得可读。
My opinion is that you don't know and shouldn't guess. Trying to outsmart compilers these days is fruitless.
There have been times people learned "Patterns" that seemed to optimize some operation, but in the next version of Java those patterns were actually slower.
Always write it as clear as you possibly can and don't worry about optimization until you actually have some user spec in your hand and are failing to meet some requirement, and even then be very careful to run before and after tests to ensure that your "fix" actually improved it enough to make that requirement pass.
The compiler can do some amazing things that would really blow your socks off, and even if you make some test that iterates over some large range, it may perform completely differently if you have a smaller range or change what happens inside the loop.
Just in time compiling means it can occasionally outperform C, and there is no reason it can't outperform static assembly language in some cases (assembly can't determine beforehand that a call isn't required, Java can at times do just that.
To sum it up: the most value you can put into your code is to write it to be readable.
没有区别。 Java 会将增强的 for 转换为普通的 for 循环。 增强的 for 只是一个“语法糖”。 两个循环生成的字节码相同。
There is no difference. Java will transform the enhanced for into the normal for loop. The enhanced for is just a "syntax sugar". The bytecode generated is the same for both loops.
为什么不自己测量一下呢?
这听起来有点刺耳,但这种问题很容易自己验证。
只需创建数组并执行每个循环 1000 次或更多次,然后测量时间量即可。 重复几次即可消除故障。
Why not measure it yourself?
This sounds a bit harsh, but this kind of questions are very easy to verify yourself.
Just create the array and execute each loop 1000 or more times, and measure the amount of time. Repeat several times to eliminate glitches.
即使在我之前回答过之后,我还是对你的问题感到非常好奇。 所以我决定自己也去检查一下。 我写了一小段代码(请忽略检查数字是否为素数的数学正确性;-)):
运行应用程序为我提供了以下结果:
正如我们所看到的,结果之间的变化非常小,有时普通循环运行得更快,有时增强循环运行得更快。 由于我的电脑上还有其他应用程序打开,所以我觉得很正常。 另外,只有第一次执行比其他执行慢——我相信这与 JIT 优化有关。
正常循环的平均时间(不包括第一次重复)为 5535.25 毫秒,增强循环的平均时间为 5547 毫秒。 但是我们可以看到两个循环的最佳运行时间是相同的(5531ms),所以我认为我们可以得出这样的结论:两个循环具有相同的性能 - 并且所用时间的变化是由于其他应用程序(甚至机器的操作系统)。
I got very curious about your question, even after my previous answer. So I decided to check it myself too. I wrote this small piece of code (please ignore math correctness about checking if a number is prime ;-)):
Running the app gave the following results for me:
As we can see, the variation among the results is very small, and sometimes the normal loop runs faster, sometimes the enhanced loop is faster. Since there are other apps open in my computer, I find it normal. Also, only the first execution is slower than the others -- I believe this has to do with JIT optimizations.
Average times (excluding the first repetition) are 5535,25ms for the normal loop and 5547ms for the enhanced loop. But we can see that the best running times for both loops is the same (5531ms), so I think we can come to the conclusion that both loops have the same performance -- and the variations of time elapsed are due to other applications (even the OS) of the machine.