在纳秒内,Java中的简单操作需要多长时间?

时间:2014-09-15 21:24:17

标签: java

我正在学习算法和算法分析课程。我想知道一个简单的操作+-/*可以在我的计算机上进行多少操作。所以我写了一个简单的秒表如下:

public class NanosecondsStopWatch implements StopWatch {

    private PrintStream stream;

    public NanosecondsStopWatch(PrintStream stream) {
        this.stream = stream;
    }

    @Override
    public void timeAndPrint(Action action) {

        long start = System.nanoTime();

        action.doAction();

        long end = System.nanoTime();

        stream.println(end-start);
    }

}


public class TestingOperationsTime {

    public static void main(String[] strings) {

        StopWatch watch = new NanosecondsStopWatch(System.out);

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2*2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2/2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2-2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2+2;
            }
        });

    }
}

结果如下

2529
454
355
335

但是,如果我改变操作的顺序,请说如下:

public class TestingOperationsTime {

    public static void main(String[] strings) {

        StopWatch watch = new NanosecondsStopWatch(System.out);

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2-2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2*2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2/2;
            }
        });

        watch.timeAndPrint(new Action() {
            @Override
            public void doAction() {
                int i= 2+2;
            }
        });

    }
}

结果仍然几乎相同:

2494
332
309
326 

你怎么解释这种行为?

  • 操作系统:Ubuntu 14.04
  • Java:1.7.0_65
  • OpenJDK运行时环境(IcedTea 2.5.1)(7u65-2.5.1-4ubuntu1~0.14.04.2)
  • OpenJDK 64位服务器VM(内置24.65-b04,混合模式)
  • javac 1.7.0_67

5 个答案:

答案 0 :(得分:5)

有许多因素会影响代码使用的系统时间。例如,如果计算机在您的代码运行时执行context switch,则您获得的时间包括运行其他程序所花费的时间。

为了缓解这种情况,您可以多次运行计时器,比如数千或数百万,并取平均值。

另外,正如@rgettman指出的那样,编译器很可能会优化这些计算,因为它们是在常量值上执行的。这意味着您只计算调用方法和打印输出的开销,而不是执行计算的时间。

答案 1 :(得分:2)

总会有差异,因为您的计算机上还运行其他进程,并且根据操作系统,某些进程将优先于其他进程。您无法确切地预测单个操作需要多少毫秒。它还取决于您的计算机CPU速度。

答案 2 :(得分:2)

编译器在编译时计算常量表达式,你应该使它成为一个接收参数的方法。

其次,对手表的系统调用需要花费几纳秒的时间,所以这个检查永远不会成为现实,你实际得到的是java花多少时间来获取时间。

答案 3 :(得分:1)

这不是一件简单的事情。 简而言之,Java不是衡量事物的正确语言。

Java是一种即时编译语言。这意味着您编写的代码在“虚拟机”中运行,并且可能是完全解释,完全编译或部分编译。 这就是为什么,一般来说,第一次运行总是较慢:它总是被解释。只有在以后,VM才能决定编译它并将已编译的代码与解释过程交换。

此外,从JVM调用系统过程会产生很大的开销,这会以某种方式改变您的测量结果。所以,是的,你可以进行测量,如果你先做一个“预热”循环,让VM知道必须编译给定的方法,然后丢弃第一个结果。但结果并不完全衡量CPU的性能。您应该使用C或汇编程序,即使在这种情况下,您也必须处理上下文切换和操作系统管理,这会改变您的结果。

PS:是的,我没有提到它,因为已经有4个其他答案,但Java编译器并不是那么愚蠢,它将在编译时评估常量操作。 i=2*2已编译为i=4,因此您不是在测量乘法时间,而是仅测量分配时间。

答案 4 :(得分:0)

2个主要问题(1)你正在调用一个消耗大量资源的函数。 (2)你只执行一次。如果直接运行该语句,或者多次运行它,您将看到执行时间非常短。结果如下time=0ns

public class PerfTest {
public static void main(String[] args) {
    long t1 = System.nanoTime();
    int i = 2 * 2;
    long t2 = System.nanoTime();
    System.out.printf("time=%dns", t2 -t1);
}

}