Java:int和double取0 millisecons进行1亿次简单计算

Xin*_*Xin 1 java double int

我正在用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纳秒

gaw*_*awi 7

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)

很酷,嘿?


Gor*_*ley 6

这是因为你写的不是价值100000000,它是三个值100,000,000,由逗号运算符,其评估两个操作数的分隔,并返回右边的一个值.永远不会输入你的循环,因为100,000,000 == (100,0),0 == 0,0 == 0.

  • 对不起,我的坏,逗号就在那里,因为人们更容易阅读.我会修好它. (3认同)