【问题标题】:How long does a simple operation take in Java in nano seconds?在 Java 中,一个简单的操作在纳秒内需要多长时间?
【发布时间】:2014-09-15 21:24:17
【问题描述】:

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

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

【问题讨论】:

  • 因为它们是常量表达式,所以2*22/22-22+2 在编译时进行评估。您的时间不反映计算时间。
  • Is there a stopwatch in java 的可能重复项
  • 如果您想知道某件事需要多长时间,请多次执行该操作,然后计算平均值。
  • 如果执行多次,结果会小于1ns。

标签: java


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        PS:是的,我没有提到它,因为已经有 4 个其他答案,但是 Java 编译器并不是那么愚蠢,它会在编译时评估常量操作。 i=2*2 被编译为 i=4,所以你测量的不是乘法时间,而是赋值时间。

        【讨论】:

        • “Java 不是衡量事物的正确语言。”如果您想知道 Java 需要多长时间,唯一的语言是 Java。然而,微基准测试很难得到正确,在使用即时编译器的运行时更难。
        【解决方案5】:

        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);
        }
        

        }

        【讨论】:

          猜你喜欢
          • 2023-04-11
          • 2019-02-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-02
          • 2020-01-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多