Java 基本数组的现代for循环
基本数组上的for循环之间是否存在性能差异 假设:Java 基本数组的现代for循环,java,performance,arrays,iteration,Java,Performance,Arrays,Iteration,基本数组上的for循环之间是否存在性能差异 假设: double[] doubleArray = new double[300000]; for (double var: doubleArray) someComplexCalculation(var); 或: 因此,现代循环实际上运行得更快,至少在我的Mac OSX JVM 1.5上是这样 为什么不自己测量呢 这听起来有点刺耳,但这类问题很容易让你自己验证 只需创建数组并执行每个循环1000次或更多次,然后测量时间量。重复几次以消
double[] doubleArray = new double[300000];
for (double var: doubleArray)
someComplexCalculation(var);
或:
因此,现代循环实际上运行得更快,至少在我的Mac OSX JVM 1.5上是这样 为什么不自己测量呢 这听起来有点刺耳,但这类问题很容易让你自己验证
只需创建数组并执行每个循环1000次或更多次,然后测量时间量。重复几次以消除故障。没有区别。Java将增强的for转换为普通的for循环。增强的for只是一个“语法糖”。两个循环生成的字节码是相同的。我的观点是,您不知道也不应该猜测。如今,试图智胜编译器是徒劳的 有些时候,人们学习“模式”似乎可以优化某些操作,但在下一版本的Java中,这些模式实际上要慢一些 始终尽可能清楚地写出来,不要担心优化问题,直到您手中确实有一些用户规范,并且无法满足某些需求,甚至在测试之前和之后都要非常小心地运行,以确保您的“修复”实际改进了它,足以使该需求通过 编译器可以做一些令人惊讶的事情,这会让你大吃一惊,即使你做了一些在某个大范围内迭代的测试,如果你有一个较小的范围或者改变了循环中发生的事情,它的性能可能会完全不同 即时编译意味着它有时可以超越C,在某些情况下它没有理由不能超越静态汇编语言(汇编无法事先确定不需要调用,Java有时可以做到这一点) 总而言之:你能在代码中投入的最大价值就是把它写得可读。你手写的“旧”形式执行的指令更少,而且可能更快,尽管你必须在给定的JIT编译器下对其进行分析才能确定。而“新”形式肯定不会更快 如果您查看反汇编代码(由Sun的JDK 1.5编译),您将看到“新”表单相当于以下代码:
1: double[] tmp = doubleArray;
2: for (int i = 0, y = tmp.length; i < y; i++) {
3: double var = tmp[i];
4: someComplexCalculation(var);
5: }
1:double[]tmp=doubleArray;
2:for(int i=0,y=tmp.length;i
因此,您可以看到使用了更多的局部变量。第1行的doubleArray
到tmp
的赋值是“额外的”,但它不会出现在循环中,并且可能无法测量。第3行的var
赋值也是额外的。如果性能有差异,这将负责
第1行似乎没有必要,但如果数组是在进入循环之前由方法计算的,那么它就是缓存结果的样板
也就是说,我会使用新表单,除非您需要使用索引变量。任何性能差异都可能在运行时被JIT编译器优化掉,并且新表单更加清晰。如果您继续“手工”完成,您可能会错过未来的优化。通常,一个好的编译器可以优化“愚蠢”代码编写得很好,但无意中发现了“智能”代码。我对你的问题很好奇,甚至在我之前的回答之后。所以我决定自己也检查一下。我写了这段小代码(请忽略检查数字是否为素数的数学正确性;-):
public class TestEnhancedFor{
公共静态void main(字符串参数[]){
针对()的新测试增强;
}
公共测试取消(){
int numberOfItems=100000;
double[]项=GetArrayFitems(numberOfItems);
整数重复=0;
漫长的开始,漫长的结束;
做{
start=System.currentTimeMillis();
DONOMALFOR(项目);
end=System.currentTimeMillis();
System.out.printf(“重复%d的正常值:%d\n”,
重复,结束-开始);
start=System.currentTimeMillis();
不取消(项目);
end=System.currentTimeMillis();
System.out.printf(“针对重复%d的增强:%d\n\n”,
重复,结束-开始);
}而(++重复次数<5次);
}
私人双[]GetArrayFitems(int numberOfItems){
double[]项目=新的double[numberOfItems];
对于(int i=0;i
运行应用程序为我提供了以下结果:
正常的。重复0:5594
增强的。重复0:5594
正常的。重复1:5531
增强的。重复1:5547
正常的。重复2:5532
增强的。重复2:5578
正常的。重复3:5531
增强的。重复3:5531
正常的。重复4:5547
增强的。重复4:5532
正如我们所见,结果之间的差异非常小,有时正常循环运行得更快,有时增强循环运行得更快。由于我的电脑中还有其他应用程序打开,我觉得这很正常。而且,只有第一次执行比其他执行慢——我相信这与JIT优化有关
正常环路的平均时间(不包括第一次重复)为5535,25ms,增强环路的平均时间为5547ms。但我们可以看到,对这两种情况来说,最佳运行时间
Total timeused for modern loop= 13269ms
Total timeused for old loop = 15370ms
1: double[] tmp = doubleArray;
2: for (int i = 0, y = tmp.length; i < y; i++) {
3: double var = tmp[i];
4: someComplexCalculation(var);
5: }
public class TestEnhancedFor {
public static void main(String args[]){
new TestEnhancedFor();
}
public TestEnhancedFor(){
int numberOfItems = 100000;
double[] items = getArrayOfItems(numberOfItems);
int repetitions = 0;
long start, end;
do {
start = System.currentTimeMillis();
doNormalFor(items);
end = System.currentTimeMillis();
System.out.printf("Normal For. Repetition %d: %d\n",
repetitions, end-start);
start = System.currentTimeMillis();
doEnhancedFor(items);
end = System.currentTimeMillis();
System.out.printf("Enhanced For. Repetition %d: %d\n\n",
repetitions, end-start);
} while (++repetitions < 5);
}
private double[] getArrayOfItems(int numberOfItems){
double[] items = new double[numberOfItems];
for (int i=0; i < numberOfItems; i++)
items[i] = i;
return items;
}
private void doSomeComplexCalculation(double item){
// check if item is prime number
for (int i = 3; i < item / 2; i+=2){
if ((item / i) == (int) (item / i)) break;
}
}
private void doNormalFor(double[] items){
for (int i = 0; i < items.length; i++)
doSomeComplexCalculation(items[i]);
}
private void doEnhancedFor(double[] items){
for (double item : items)
doSomeComplexCalculation(item);
}
}