我正在用double进行一些简单的测试,如下所示:
startTime = System.currentTimeMillis();
for (int i = 0; i < 100_000_000; i++)
{
doubleCalcTest();
}
endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " nanoseconds");
Run Code Online (Sandbox Code Playgroud)
.
public static double doubleCalcTest()
{
double x = 987.654321;
double y = 123.456789;
x = x + y;
x = x - y;
x = x * y;
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
事实证明输出是0毫秒.这对我没有意义,因为如果我将for循环设置为仅运行100,000次,则输出为3毫秒.我发现int也以同样的方式行事.
任何人都可以帮我一把吗?谢谢.
我更改了我的代码以调用'System.nanoTime'时间并传递一个double值,该值按照建议的循环索引递增.
double x = 123.456789
startTime = System.nanoTime();
for (int i = 0; i < 100_000_000; i++)
{
x = x + i;
doubleCalcTest(x);
}
endTime = System.nanoTime();
System.out.println("That took " + (endTime - startTime) + " nanoseconds");
Run Code Online (Sandbox Code Playgroud)
.
public static double doubleCalcTest(double x)
{
double y = 123.456789;
x = x + y;
x = x - y;
x = x * y;
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
运行10,000次需要503,200纳秒
运行10,000,000次需要3,421纳秒
JIT放弃执行,DoubleCalcTest因为它没有任何副作用(纯计算)并且结果未被使用.由于没有效果,循环本身也可以被优化.
尝试使用JIT关闭,大约需要8000毫秒:
java -Xint snippet.Snippet
Run Code Online (Sandbox Code Playgroud)
在byteocde级别,没有任何优化.
javap -c snippet.Snippet
Run Code Online (Sandbox Code Playgroud)
结果:
public class snippet.Snippet {
public snippet.Snippet();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #16 // Method java/lang/System.currentTimeMillis:()J
3: lstore_1
4: iconst_0
5: istore_3
6: goto 16
9: invokestatic #22 // Method DoubleCalcTest:()D
12: pop2
13: iinc 3, 1
16: iload_3
17: ldc #26 // int 100000000
19: if_icmplt 9
22: invokestatic #16 // Method java/lang/System.currentTimeMillis:()J
25: lstore_3
26: getstatic #27 // Field java/lang/System.out:Ljava/io/PrintStream;
29: new #31 // class java/lang/StringBuilder
32: dup
33: ldc #33 // String That took
35: invokespecial #35 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
38: lload_3
39: lload_1
40: lsub
41: invokevirtual #38 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
44: ldc #42 // String milliseconds
46: invokevirtual #44 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
49: invokevirtual #47 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
52: invokevirtual #51 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: return
public static double DoubleCalcTest();
Code:
0: ldc2_w #64 // double 987.654321d
3: dstore_0
4: ldc2_w #66 // double 123.456789d
7: dstore_2
8: dload_0
9: dload_2
10: dadd
11: dstore_0
12: dload_0
13: dload_2
14: dsub
15: dstore_0
16: dload_0
17: dload_2
18: dmul
19: dstore_0
20: dload_0
21: dload_2
22: ddiv
23: dreturn
}
Run Code Online (Sandbox Code Playgroud)
如果您尝试使用DoubleCalc()的结果,将其分配给变量并在之后打印它.
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
double res = 0;
for (int i = 0; i < 100000000; i++) {
res = DoubleCalcTest();
}
System.out.println(res);
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
}
Run Code Online (Sandbox Code Playgroud)
这将花费相同的时间.为什么?JIT似乎足够聪明,可以理解结果不依赖于迭代完成的次数.
但是,如果您将其更改为:
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
double res = 0;
for (int i = 0; i < 100000000; i++) {
res += DoubleCalcTest();
}
System.out.println(res);
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
}
Run Code Online (Sandbox Code Playgroud)
结果取决于迭代次数,JIT不会进一步优化.在这种情况下,大约需要100毫秒.如果我为200000000更改100000000,则需要两倍的时间.
所以结论是JIT在那里停止了.
注意:
对于给C程序:
#include <stdio.h>
int main(int argc, char** argv) {
long x = 0;
int i;
for(i=0; i<1000000; i++) {
x+=i;
}
printf("%ld", x);
}
Run Code Online (Sandbox Code Playgroud)
GCC能够完全优化循环并在编译时计算x的值:
gcc -O2 -S main.c
Run Code Online (Sandbox Code Playgroud)
电源:
.file "main.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%ld"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
movabsq $499999500000, %rsi <---- See, this is the pre-computed result
movl $.LC0, %edi
xorl %eax, %eax
jmp printf
.cfi_endproc
.LFE11:
.size main, .-main
.ident "GCC: (GNU) 4.7.2 20121109 (Red Hat 4.7.2-8)"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
很酷,嘿?
这是因为你写的不是价值100000000,它是三个值100,000,000,由逗号运算符,其评估两个操作数的分隔,并返回右边的一个值.永远不会输入你的循环,因为100,000,000 == (100,0),0 == 0,0 == 0.
| 归档时间: |
|
| 查看次数: |
248 次 |
| 最近记录: |