如何在 Java 中计时方法的执行?
Posted
技术标签:
【中文标题】如何在 Java 中计时方法的执行?【英文标题】:How do I time a method's execution in Java? 【发布时间】:2010-09-15 20:40:14 【问题描述】:-
如何获取方法的执行时间?
是否有一个
Timer
实用程序类用于计时任务需要多长时间等?
Google 上的大多数搜索都返回了用于安排线程和任务的计时器的结果,这不是我想要的。
【问题讨论】:
JAMon API 是一个免费、简单、高性能、线程安全的 Java API,它允许开发人员轻松监控生产应用程序的性能和可扩展性。 JAMon 跟踪命中、执行时间(总、平均、最小值、最大值、标准差)等。 http://jamonapi.sourceforge.net/ 下载:http://sourceforge.net/project/showfiles.php?group_id=96550 您可能还想查看Apache Commons Lang StopWatch 类。一个简单但有用的实用程序类。 后期类似问题:How do I write a correct micro-benchmark in Java? 是的,秒表非常适合。 Java 8 使用Instant
类:***.com/a/30975902/1216775
【参考方案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 中对我有用的策略是:
用@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;
注释你要监控的方法:
@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);
这足以传递Runnable 或Callable。
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;
【讨论】:
以上是关于如何在 Java 中计时方法的执行?的主要内容,如果未能解决你的问题,请参考以下文章