And*_*anu 7 java optimization performance
提供以下(直接)代码:
public class pr1 {
public static void f1(){
long sx = 0, s;
s = System.currentTimeMillis();
for(long i = 0; i < Integer.MAX_VALUE; ++i){
sx += i;
}
System.out.println("f1(): " + (System.currentTimeMillis() - s));
}
public static void f2(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(i-->0){
sx+=i;
}
sx += Integer.MAX_VALUE;
System.out.println("f2(): " + (System.currentTimeMillis() - s));
}
public static void f3(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(--i>0){
sx+=i;
}
sx += Integer.MAX_VALUE;
System.out.println("f3(): " + (System.currentTimeMillis() - s));
}
public static void f4(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
do{
sx+=i;
}while(--i>0);
System.out.println("f4(): " + (System.currentTimeMillis() - s));
}
public static void main(String args[]){
f1();
f2();
f3();
f4();
}
}
Run Code Online (Sandbox Code Playgroud)
以及运行代码后的实际结果:
f1(): 5828
f2(): 8125
f3(): 3406
f4(): 3781
Run Code Online (Sandbox Code Playgroud)
能否请您解释一下时间的巨大差异?理论上,循环实现了相同的功能,但在实践中,似乎四个版本中的每一个都存在相关的时间差异.
重复执行后,结果非常相似.
后期编辑 作为另一项测试我改写了主要方法:
public static void main(String args[]){
for(int i = 0; i < 4; ++i){
f1(); f2(); f3(); f4();
}
}
Run Code Online (Sandbox Code Playgroud)
新的结果是:
f1(): 5906
f2(): 8266
f3(): 3406
f4(): 3844
f1(): 5843
f2(): 8125
f3(): 3438
f4(): 3859
f1(): 5891
f2(): 8156
f3(): 3406
f4(): 3813
f1(): 5859
f2(): 8172
f3(): 3438
f4(): 3828
Run Code Online (Sandbox Code Playgroud)
10次重复:
f1(): 5844
f2(): 8156
f3(): 3453
f4(): 3813
f1(): 5844
f2(): 8218
f3(): 3485
f4(): 3937
f1(): 5985
f2(): 8156
f3(): 3422
f4(): 3781
f1(): 5828
f2(): 8234
f3(): 3469
f4(): 3828
f1(): 5844
f2(): 8328
f3(): 3422
f4(): 3859
f1(): 5844
f2(): 8188
f3(): 3406
f4(): 3797
f1(): 5906
f2(): 8219
f3(): 3422
f4(): 3797
f1(): 5843
f2(): 8203
f3(): 3454
f4(): 3906
f1(): 5844
f2(): 8140
f3(): 3469
f4(): 3812
f1(): 5860
f2(): 8109
f3(): 3422
f4(): 3813
Run Code Online (Sandbox Code Playgroud)
在去除循环之间的微积分后,结果仍然有点不同:
public class pr2 {
public static void f1(){
long sx = 0, s;
s = System.currentTimeMillis();
for(long i = 0; i < Integer.MAX_VALUE; ++i);
System.out.println("f1(): " + (System.currentTimeMillis() - s));
}
public static void f2(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(i-->0);
System.out.println("f2(): " + (System.currentTimeMillis() - s));
}
public static void f3(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(--i>0);
System.out.println("f3(): " + (System.currentTimeMillis() - s));
}
public static void f4(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
do{
}while(--i>0);
System.out.println("f4(): " + (System.currentTimeMillis() - s));
}
public static void main(String args[]){
for(int i = 0; i < 2; ++i){
f1(); f2(); f3(); f4();
}
}
}
Run Code Online (Sandbox Code Playgroud)
但时差仍然存在:
f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031
f1(): 3219
f2(): 4812
f3(): 2610
f4(): 3062
Run Code Online (Sandbox Code Playgroud)
JVM:
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Client VM (build 16.3-b01, mixed mode, sharing)
Run Code Online (Sandbox Code Playgroud)
LATER EDIT: 对于第一个版本,我使用了-av参数为javac.新的结果是:
f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031
Run Code Online (Sandbox Code Playgroud)
稍后编辑
好的,我在家里尝试使用相同的代码,使用Linux机器:
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8) (6b18-1.8-0ubuntu1)
OpenJDK Server VM (build 14.0-b16, mixed mode)
Run Code Online (Sandbox Code Playgroud)
结果是"正常的".现在没问题:
f1(): 7495
f2(): 7418
f3(): 7457
f4(): 7384
Run Code Online (Sandbox Code Playgroud)
Bal*_*usC 10
您实际上是对JVM进行基准测试,而不是代码.
更新:好的,这是一个有点简单的回答.使用后缀运算符(i--)的循环似乎比使用前缀运算符(--i)的循环慢.这可能是真的,因为在评估表达式期间更改了值,但编译器需要保存要在表达式中使用的原始值的副本.使用前缀运算符可以避免保留副本,因为只需在表达式中使用更改的值.
毕竟,这次微观优化会在2 31次执行中为你节省一两秒钟.您是否真的经常执行它?我更喜欢可读性而不是过早优化.
当我在我的JVM(Java HotSpot(TM)64位服务器VM(构建16.0-b13,混合模式))上运行此代码时,所有四个函数都给出类似的结果:
f1(): 3234
f2(): 3132
f3(): 3114
f4(): 3089
Run Code Online (Sandbox Code Playgroud)
我猜你的JVM并没有在某处进行相同的优化.
您可以使用javap检查为不同函数生成的字节码:javap -l -c pr1.当我这样做时,我得到f2()的以下内容:
public static void f2();
Code:
0: lconst_0
1: lstore_0
2: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
5: lstore_2
6: ldc2_w #3; //long 2147483647l
9: lstore 4
11: lload 4
13: dup2
14: lconst_1
15: lsub
16: lstore 4
18: lconst_0
19: lcmp
20: ifle 31
23: lload_0
24: lload 4
26: ladd
27: lstore_0
28: goto 11
31: lload_0
32: ldc2_w #3; //long 2147483647l
35: ladd
36: lstore_0
37: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
40: new #6; //class java/lang/StringBuilder
43: dup
44: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V
47: ldc #13; //String f2():
49: invokevirtual #9; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
52: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
55: lload_2
56: lsub
57: invokevirtual #10; //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
60: invokevirtual #11; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
63: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: return
Run Code Online (Sandbox Code Playgroud)
f2()较慢的一个可能原因可能是编译器/ JVM对while(i-->0)后递减运算符不聪明.基本上,您需要i增量之前和之后的值,因此如果天真地实现,此操作涉及更多工作.