【问题标题】:How to time Java program execution speed如何计时Java程序执行速度
【发布时间】:2010-04-03 22:24:20
【问题描述】:

你如何为 java 程序的执行计时?我不确定我应该使用哪个类来执行此操作。

我正在寻找类似的东西:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);

【问题讨论】:

    标签: java


    【解决方案1】:
    final long startTime = System.currentTimeMillis();
    for (int i = 0; i < length; i++) {
      // Do something
    }
    final long endTime = System.currentTimeMillis();
    
    System.out.println("Total execution time: " + (endTime - startTime));
    

    【讨论】:

    • 实际上应该是 nanoTime
    • 不应该是 nanoTime。请参阅 rhu 的回答。
    • 您在这里使用“final”有什么特别的原因吗?如果您删除该关键字会有什么不同?
    • @dijxtra 使用final 的优点是您不会意外分配给它(以及其他优点,例如匿名类访问等)。在这段代码中,它不会有所作为。将所有内容都设为final 并仅在需要时取消finalize 是一种相当普遍的做法。
    • 要测试的代码以及时间测量应该运行多次,并且应该丢弃第一个结果。第一个可能包括类加载时间等。当然,通过多次运行它,你也会得到一个更有用和更可靠的平均值。
    【解决方案2】:

    请注意,在某些问题上,System#nanoTime() 不能可靠地用于多核 CPU 来记录经过的时间...每个内核都维护自己的 TSC (Time Stamp Counter):此计数器用于获取纳秒时间(实际上是自 CPU 启动以来的滴答数)。

    因此,除非操作系统进行一些 TSC 时间扭曲以保持内核同步,否则如果在读取初始时间时线程被安排在一个内核上,然后切换到另一个内核,则相对时间可能会偶尔出现前后跳跃。

    我前段时间在 AMD/Solaris 上观察到这一点,其中两个时间点之间的经过时间有时会以负值或意外的大正数返回。强制 AMD PowerNow! 需要 Solaris 内核补丁和 BIOS 设置。关闭,这似乎解决了它。

    此外,在 VirtualBox 环境中使用 java System#nanoTime() 时,存在 (AFAIK) 一个迄今为止未修复的错误;由于java.util.concurrency 包的大部分依赖于纳米时间,因此给我们带来了各种奇怪的间歇性线程问题。

    另见:

    Is System.nanoTime() completely useless? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html

    【讨论】:

      【解决方案3】:

      你得到当前系统时间,以毫秒为单位:

      final long startTime = System.currentTimeMillis();
      

      然后你做你想做的事:

      for (int i = 0; i < length; i++) {
        // Do something
      }
      

      那你看看花了多长时间:

      final long elapsedTimeMillis = System.currentTimeMillis() - startTime;
      

      【讨论】:

      • BalusC 的回答也是正确的;这取决于所需的计时器分辨率,以及为什么需要计时。
      【解决方案4】:

      您可以使用System#nanoTime()。在执行之前和之后获取它,然后进行数学计算。它在System#currentTimeMillis() 以上是首选,因为它具有更好的精度。根据所使用的硬件和平台,您可能会得到不正确的经过时间间隔。在 Windows 上使用 Core2Duo,大约 0 到 ~15ms 之间实际上没有什么可以计算的。

      更高级的工具是profiler

      【讨论】:

      • Windows 上的计时器默认没有特别好的分辨率。 也有一个高性能计时器,但即使使用 C 和 Java 也很难使用(AFAIK)在没有 JNI thunk 的情况下提供对低级别黑客的访问。
      • nanoTime() 有一个问题(至少在 Windows 上);时间戳特定于处理器内核。我有一个程序的执行时间为负,因为它在一个内核上获得了“开始”时间戳,而在另一个内核上获得了“停止”时间戳。
      【解决方案5】:

      这里有几种在 Java 中查找执行时间的方法:

      1) System.nanoTime()

      long startTime = System.nanoTime();
      .....your code....
      long endTime   = System.nanoTime();
      long totalTime = endTime - startTime;
      System.out.println("Execution time in nanoseconds  : " + totalTime);
      System.out.println("Execution time in milliseconds : " + totalTime / 1000000);
      

      2) System.currentTimeMillis()

      long startTime = System.currentTimeMillis();
      .....your code....
      long endTime = System.currentTimeMillis();
      long totalTime = endTime - startTime;
      System.out.println("Execution time in milliseconds  : " + totalTime);
      

      3) Instant.now()

      long startTime = Instant.now().toEpochMilli();
      .....your code....
      long endTime = Instant.now().toEpochMilli();
      long totalTime = endTime - startTime;
      System.out.println("Execution time in milliseconds: " + totalTime);
      

      Instant start = Instant.now();
      .....your code....
      Instant end = Instant.now();
      Duration interval = Duration.between(start, end);
      System.out.println("Execution time in seconds: " +interval.getSeconds());
      

      4) Date.getTime()

      long startTime = new Date().getTime();
      .....your code....
      long endTime = new Date().getTime();
      long totalTime = endTime - startTime;
      System.out.println("Execution time in milliseconds: " + totalTime);
      

      【讨论】:

        【解决方案6】:

        对于简单的东西,System.currentTimeMillis() 可以工作。

        实际上很常见,我的 IDE 已设置,因此在输入“t0”时它会生成以下行:

        final long t0 = System.currentTimeMillis()
        

        但对于更复杂的事情,您可能希望使用统计时间测量,例如这里(向下滚动一点,查看表示的时间测量,包括标准偏差等):

        http://perf4j.codehaus.org/devguide.html

        【讨论】:

        • +1 用于指出自动生成器代码。我一直在使用类似的语句,并且不知道插入代码模板。刚刚发现如何用 eclipse 做到这一点,它肯定会有所帮助!
        • 所有 Codehaus 服务已终止。您的链接现已损坏。
        【解决方案7】:

        使用来自jcabi-aspects 的AOP/AspectJ 和@Loggable 注释,您可以轻松而紧凑地做到这一点:

        @Loggable(Loggable.DEBUG)
        public String getSomeResult() {
          // return some value
        }
        

        对该方法的每次调用都将发送到具有DEBUG 日志记录级别的 SLF4J 日志记录工具。而且每条日志消息都会包含执行时间。

        【讨论】:

          【解决方案8】:

          在循环顶部使用 long startTime=System.currentTimeMillis() 作为开始时间

          long endTime= System.currentTimeMillis(); 放在循环末尾之外。您必须减去这些值才能获得以毫秒为单位的运行时间。

          如果您想要以纳秒为单位的时间,请查看System.nanoTime()

          【讨论】:

            【解决方案9】:

            我创建了一个高阶函数,它将您要测量的代码/作为 lambda:

            class Utils {
            
                public static <T> T timeIt(String msg, Supplier<T> s) {
                    long startTime = System.nanoTime();
                    T t = s.get();
                    long endTime = System.nanoTime();
                    System.out.println(msg + ": " + (endTime - startTime) + " ns");
                    return t;
                }
            
                public static void timeIt(String msg, Runnable r) {
                   timeIt(msg, () -> {r.run(); return null; });
                }
            }
            

            这样称呼:

            Utils.timeIt("code 0", () ->
                    System.out.println("Hallo")
            );
            
            // in case you need the result of the lambda
            int i = Utils.timeIt("code 1", () ->
                    5 * 5
            );
            

            输出:

            代码 0:180528 ns
            代码 1:12003 纳秒

            特别感谢Andy Turner 帮助我减少了冗余。见here

            【讨论】:

              【解决方案10】:

              您可以使用秒表

              import com.google.common.base.Stopwatch;
              
              Stopwatch timer = Stopwatch.createStarted();
              //lines to be executed
              System.out.println("Execution time= " + timer.stop());
              

              【讨论】:

                【解决方案11】:

                【讨论】:

                  【解决方案12】:

                  您也可以尝试 Perf4J。它是一种完成您正在寻找的工作的简洁方式,并有助于汇总性能统计数据,例如在设定的时间跨度内的平均值、最小值、最大值、标准差和每秒事务数。 http://perf4j.codehaus.org/devguide.html的摘录:

                  StopWatch stopWatch = new LoggingStopWatch();
                  
                  try {
                      // the code block being timed - this is just a dummy example
                      long sleepTime = (long)(Math.random() * 1000L);
                      Thread.sleep(sleepTime);
                      if (sleepTime > 500L) {
                          throw new Exception("Throwing exception");
                      }
                  
                      stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
                  } catch (Exception e) {
                      stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
                  }
                  

                  输出:

                  INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
                  INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
                  INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
                  INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
                  INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
                  

                  【讨论】:

                    【解决方案13】:
                    public class someClass
                    {
                       public static void main(String[] args) // your app start point
                       {
                           long start = java.util.Calendar.getInstance().getTimeInMillis();
                    
                           ... your stuff ...
                    
                           long end = java.util.Calendar.getInstance().getTimeInMillis();
                           System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
                       }
                    }
                    

                    【讨论】:

                      【解决方案14】:

                      使用 System.currentTimeMillis() 是正确的方法。但是,如果您使用命令行,并且想要大致快速地为整个程序计时,请考虑:

                      time java App
                      

                      这允许您不修改应用程序的代码和时间。

                      【讨论】:

                      • 这取决于你如何运行代码。如果它是运行服务器的一段代码,那么您将包含不正确的启动时间。
                      猜你喜欢
                      • 2017-09-17
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多