【问题标题】:How do I time a method's execution in Java?如何在 Java 中计时方法的执行?
【发布时间】:2010-09-15 20:40:14
【问题描述】:
  1. 如何获取方法的执行时间?
  2. 是否有一个Timer 实用程序类用于计时任务需要多长时间等?

Google 上的大多数搜索都返回了用于安排线程和任务的计时器的结果,这不是我想要的。

【问题讨论】:

标签: java timing execution-time


【解决方案1】:

如果只是想知道时间,您可以尝试这种方式。

long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));    

【讨论】:

    【解决方案2】:

    在 Java 8 中引入了一个名为 Instant 的新类。根据文档:

    Instant 表示时间线上一纳秒的开始。这 类对于生成表示机器时间的时间戳很有用。 瞬间的范围需要存储一个大于a的数字 长。为了实现这一点,该类存储了一个长表示 epoch-seconds 和一个表示 nanosecond-of-second 的 int,这将 始终介于 0 和 999,999,999 之间。测量纪元秒数 从 1970-01-01T00:00:00Z 的标准 Java 时代开始 在 epoch 之后有正值,并且更早的时刻有 负值。对于纪元秒和纳秒部分,a 在时间线上,较大的值总是比较小的值晚。

    这可以用作:

    Instant start = Instant.now();
    try {
        Thread.sleep(7000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Instant end = Instant.now();
    System.out.println(Duration.between(start, end));
    

    它打印PT7.001S

    【讨论】:

      【解决方案3】:

      如果java有更好的功能支持就好了,这样需要度量的动作可以被包裹到一个块中:

      measure {
         // your operation here
      }
      

      在java中这可以通过匿名函数来完成,看起来太冗长了

      public interface Timer {
          void wrap();
      }
      
      
      public class Logger {
      
          public static void logTime(Timer timer) {
              long start = System.currentTimeMillis();
              timer.wrap();
              System.out.println("" + (System.currentTimeMillis() - start) + "ms");
          }
      
          public static void main(String a[]) {
              Logger.logTime(new Timer() {
                  public void wrap() {
                      // Your method here
                      timeConsumingOperation();
                  }
              });
      
          }
      
          public static void timeConsumingOperation() {
              for (int i = 0; i<=10000; i++) {
                 System.out.println("i=" +i);
              }
          }
      }
      

      【讨论】:

      • 可以通过使用 Java 8 的 lambda 表达式来清理。 drdobbs.com/jvm/lambda-expressions-in-java-8/240166764?pgno=2
      • 确实,由于 Java 8,java.lang.Runnable@FunctionalInterface,这意味着您可以将 lambda 表达式传递给任何以 Runnable 作为参数的方法。您的timeThisCode(Runnable r) 可以简单地返回毫秒/纳米或更精细的经过时间的表示。
      【解决方案4】:

      这里是漂亮的打印字符串准备好格式化的秒数,类似于谷歌搜索时间:

              long startTime = System.nanoTime();
              //  ... methodToTime();
              long endTime = System.nanoTime();
              long duration = (endTime - startTime);
              long seconds = (duration / 1000) % 60;
              // formatedSeconds = (0.xy seconds)
              String formatedSeconds = String.format("(0.%d seconds)", seconds);
              System.out.println("formatedSeconds = "+ formatedSeconds);
              // i.e actual formatedSeconds = (0.52 seconds)
      

      【讨论】:

      • nonoTime 不是 /1000 秒。你的数学假设 getTime 是毫秒。最好做 /1e6 以获得毫秒。
      【解决方案5】:

      我实现了一个简单的计时器,我认为它真的很有用:

      public class Timer{
          private static long start_time;
      
          public static double tic(){
              return start_time = System.nanoTime();
          }
      
          public static double toc(){
              return (System.nanoTime()-start_time)/1000000000.0;
          }
      
      }
      

      这样你就可以为一个或多个动作计时:

      Timer.tic();
      // Code 1
      System.out.println("Code 1 runtime: "+Timer.toc()+" seconds.");
      // Code 2
      System.out.println("(Code 1 + Code 2) runtime: "+Timer.toc()+"seconds");
      Timer.tic();
      // Code 3
      System.out.println("Code 3 runtime: "+Timer.toc()+" seconds.");
      

      【讨论】:

        【解决方案6】:

        您可以使用javaagent来修改java类字节,动态添加监控代码。github上有一些开源工具可以为您做到这一点。
        如果你想自己做,只需要实现javaagent,使用javassist修改你要监控的方法,在你的方法返回之前的监控代码。很干净并且您可以监控甚至没有源代码的系统。

        【讨论】:

          【解决方案7】:

          System.nanoTime() 是一个非常精确的系统实用程序,用于测量执行时间。但请注意,如果您在抢占式调度程序模式(默认)下运行,此实用程序实际上测量的是挂钟时间而不是 CPU 时间。因此,您可能会注意到每次运行的执行时间值不同,具体取决于系统负载。如果您寻找 CPU 时间,我认为以实时模式运行您的程序就可以了。你必须使用 RT linux。链接:Real-time programming with Linux

          【讨论】:

            【解决方案8】:

            在 java ee 中对我有用的策略是:

            1. @AroundInvoke注解的方法创建一个类;

              @Singleton
              public class TimedInterceptor implements Serializable {
              
                  @AroundInvoke
                  public Object logMethod(InvocationContext ic) throws Exception {
                      Date start = new Date();
                      Object result = ic.proceed();
                      Date end = new Date();
                      System.out.println("time: " + (end.getTime - start.getTime()));
                      return result;
                  }
              }
              
            2. 注释你要监控的方法:

              @Interceptors(TimedInterceptor.class)
              public void onMessage(final Message message) { ... 
              

            我希望这会有所帮助。

            【讨论】:

              【解决方案9】:

              对于 java 8+,另一种可能的解决方案(更通用,func 样式且没有方面)可能是创建一些实用方法,接受代码作为参数

              public static <T> T timed (String description, Consumer<String> out, Supplier<T> code) {
                  final LocalDateTime start = LocalDateTime.now ();
                  T res = code.get ();
                  final long execTime = Duration.between (start, LocalDateTime.now ()).toMillis ();
                  out.accept (String.format ("%s: %d ms", description, execTime));
                  return res;
              }
              

              调用代码可能是这样的:

              public static void main (String[] args) throws InterruptedException {
                  timed ("Simple example", System.out::println, Timing::myCode);
              }
              
              public static Object myCode () {
                  try {
                      Thread.sleep (1500);
                  } catch (InterruptedException e) {
                      e.printStackTrace ();
                  }
                  return null;
              }
              

              【讨论】:

                【解决方案10】:

                也可以实现 Timer 接口并在你的类的任何方法上执行

                import java.util.function.*;
                
                public interface Timer {
                
                    default void timeIt(Runnable r) {
                        timeIt(() -> { r.run(); return 0;});
                    }
                
                    default <S,T> T timeIt(Function<S,T> fun, S arg) {
                        long start = System.nanoTime();
                        T result = fun.apply(arg);
                        long stop = System.nanoTime();
                        System.out.println("Time: " + (stop-start)/1000000.0 + " msec");
                        return result;
                    }
                
                    default <T> T timeIt(Supplier<T> s) {
                        return timeIt(obj -> s.get(), null);
                    }
                }
                

                用法:

                class MyClass implements Timer ..
                
                timeIt(this::myFunction); 
                

                【讨论】:

                  【解决方案11】:

                  这里有很多有效的答案,所有这些都是在方法中实现的。为了制作一个通用的计时方法,我通常有一个 Timing 类,包含以下内容。

                  public record TimedResult<T>(T result, Duration duration) {}
                  
                  public static Duration time(Runnable r) {
                      var s = Instant.now();
                      r.run();
                      var dur = Duration.between(s, Instant.now());
                      return dur;
                  }
                  
                  public static <T> TimedResult<T> time(Callable<T> r) throws Exception {
                      var s = Instant.now();
                      T res = r.call();
                      var dur = Duration.between(s, Instant.now());
                      return new TimedResult<>(res, dur);
                  }
                  

                  这足以传递RunnableCallable

                  Duration result = Timing.time(() -> {
                      // do some work.
                  });
                  
                  TimedResult<String> result = Timing.time(() -> {
                      // do some work.
                      return "answer";
                  });
                  
                  Duration timeTaken = result.duration();
                  String answer = result.result();
                  

                  【讨论】:

                    【解决方案12】:

                    纯Java SE代码,无需添加依赖,使用TimeTracedExecuter

                    public static void main(String[] args) {
                    
                        Integer square = new TimeTracedExecutor<>(Main::calculateSquare)
                                    .executeWithInput("calculate square of num",5,logger);
                    
                    }
                    public static int calculateSquare(int num){
                        return num*num;
                    }
                    

                    会产生这样的结果:

                    INFO: It took 3 milliseconds to calculate square of num

                    自定义可重用类:TimeTracedExecutor

                    import java.text.NumberFormat;
                    import java.time.Duration;
                    import java.time.Instant;
                    import java.util.function.Function;
                    import java.util.logging.Logger;
                    
                    public class TimeTracedExecutor<T,R> {
                        Function<T,R> methodToExecute;
                    
                        public TimeTracedExecutor(Function<T, R> methodToExecute) {
                            this.methodToExecute = methodToExecute;
                        }
                    
                        public R executeWithInput(String taskDescription, T t, Logger logger){
                            Instant start = Instant.now();
                            R r= methodToExecute.apply(t);
                            Instant finish = Instant.now();
                            String format = "It took %s milliseconds to "+taskDescription;
                            String elapsedTime = NumberFormat.getNumberInstance().format(Duration.between(start, finish).toMillis());
                            logger.info(String.format(format, elapsedTime));
                            return r;
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2022-01-21
                      • 2014-08-06
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-11-03
                      相关资源
                      最近更新 更多