如何在Java中计算方法的执行时间?
我如何获得一个方法的执行时间? 是否有一个定时器实用程序类的时间多久,任务需要等等?
Google上的大多数search都会返callback度线程和任务的定时器的结果,这不是我想要的。
总是有老套的方式:
long startTime = System.nanoTime(); methodToTime(); long endTime = System.nanoTime(); long duration = (endTime - startTime); //divide by 1000000 to get milliseconds.
我用简单的答案去。 为我工作。
long startTime = System.currentTimeMillis(); doReallyLongThing(); long endTime = System.currentTimeMillis(); System.out.println("That took " + (endTime - startTime) + " milliseconds");
它工作得很好。 分辨率显然只有毫秒,你可以用System.nanoTime()做的更好。 两者(操作系统时间片等)都有一些限制,但是这个工作很好。
平均数跑(越多越好),你会得到一个体面的想法。
拜托了伙计们! 没有人提到番石榴的方式做到这一点(这是可怕的):
import com.google.common.base.Stopwatch; Stopwatch timer = Stopwatch.createStarted(); //method invocation LOG.info("Method took: " + timer.stop());
好的是,Stopwatch.toString()为测量select时间单位做得很好。 也就是说,如果值很小,它将输出38 ns,如果它很长,它将显示5m 3s
更好:
Stopwatch timer = Stopwatch.createUnstarted(); for (...) { timer.start(); methodToTrackTimeFor(); timer.stop(); methodNotToTrackTimeFor(); } LOG.info("Method took: " + timer);
注意:Google Guava需要Java 1.6+
使用Java 8新API的Instant和Duration ,
Instant start = Instant.now(); Thread.sleep(5000); Instant end = Instant.now(); System.out.println(Duration.between(start, end));
输出,
PT5S
使用分析器(JProfiler,Netbeans Profiler,Visual VM,Eclipse Profiler等)。 你会得到最准确的结果,是最没有侵入性的。 他们使用内置的JVM机制进行性能分析,如果需要,还可以为您提供额外的信息,如堆栈跟踪,执行path和更全面的结果。
当使用一个完全集成的分析器时,分析一个方法是微不足道的。 右键单击Profiler – > Add to Root Methods。 然后像执行testing运行或debugging程序一样运行分析器。
这可能不是你想要我说的,但是这是AOP的一个很好的使用。 鞭打你的方法代理拦截器,并在那里做的时间。
不幸的是,AOP的原因,原因和方式超出了这个答案的范围,但这就是我可能做到的。
编辑: 这是一个链接到Spring AOP,让你开始,如果你热衷。 这是Iive在Java中遇到的最易于实现的AOP。
另外,考虑到其他人的非常简单的build议,我应该补充说,AOP是当你不需要像定时侵入你的代码的东西。 但是在很多情况下,这种简单易行的方法是很好的。
System.currentTimeMillis();
测量algorithm的性能不是一个好方法。 它衡量您在观看电脑屏幕的过程中所经历的总时间。 它还包括在后台运行在您的计算机上的其他一切消耗的时间。 如果您的工作站上运行了很多程序,这可能会产生巨大的差异。
正确的方法是使用java.lang.management
包。
从http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking网站:;
- “用户时间”是运行应用程序自己的代码所用的时间。
- “系统时间”是代表应用程序(例如I / O)运行OS代码所用的时间。
getCpuTime()
方法给你的总和:
import java.lang.management.ManagementFactory; import java.lang.management.ThreadMXBean; public class CPUUtils { /** Get CPU time in nanoseconds. */ public static long getCpuTime( ) { ThreadMXBean bean = ManagementFactory.getThreadMXBean( ); return bean.isCurrentThreadCpuTimeSupported( ) ? bean.getCurrentThreadCpuTime( ) : 0L; } /** Get user time in nanoseconds. */ public static long getUserTime( ) { ThreadMXBean bean = ManagementFactory.getThreadMXBean( ); return bean.isCurrentThreadCpuTimeSupported( ) ? bean.getCurrentThreadUserTime( ) : 0L; } /** Get system time in nanoseconds. */ public static long getSystemTime( ) { ThreadMXBean bean = ManagementFactory.getThreadMXBean( ); return bean.isCurrentThreadCpuTimeSupported( ) ? (bean.getCurrentThreadCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L; } }
集合了所有可能的方法到一个地方。
date
Date startDate = Calendar.getInstance().getTime(); long d_StartTime = new Date().getTime(); Thread.sleep(1000 * 4); Date endDate = Calendar.getInstance().getTime(); long d_endTime = new Date().getTime(); System.out.format("StartDate : %s, EndDate : %s \n", startDate, endDate); System.out.format("Milli = %s, ( D_Start : %s, D_End : %s ) \n", (d_endTime - d_StartTime),d_StartTime, d_endTime);
系统
long startTime = System.currentTimeMillis(); Thread.sleep(1000 * 4); long endTime = System.currentTimeMillis(); long duration = (endTime - startTime); System.out.format("Milli = %s, ( S_Start : %s, S_End : %s ) \n", duration, startTime, endTime ); System.out.println("Human-Readable format : "+millisToShortDHMS( duration ) );
Apache – 秒表
org.apache.commons.lang3.time.StopWatch sw = new StopWatch(); sw.start(); Thread.sleep(1000 * 4); sw.stop(); System.out.println("Apache StopWatch : "+ millisToShortDHMS(sw.getTime()) );
Google – 秒表
com.google.common.base.Stopwatch g_SW = Stopwatch.createUnstarted(); g_SW.start(); Thread.sleep(1000 * 4); g_SW.stop(); System.out.println("Google StopWatch : "+g_SW);
人类可读的格式
public static String millisToShortDHMS(long duration) { String res = ""; // java.util.concurrent.TimeUnit; long days = TimeUnit.MILLISECONDS.toDays(duration); long hours = TimeUnit.MILLISECONDS.toHours(duration) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)); long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)); long millis = TimeUnit.MILLISECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); if (days == 0) res = String.format("%02d:%02d:%02d.%04d", hours, minutes, seconds, millis); else res = String.format("%dd %02d:%02d:%02d.%04d", days, hours, minutes, seconds, millis); return res; }
JODA -TIME
public static void jodaTime() throws InterruptedException, ParseException{ java.text.SimpleDateFormat ms_SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); String start = ms_SDF.format( new Date() ); // java.util.Date Thread.sleep(10000); String end = ms_SDF.format( new Date() ); System.out.println("Start:"+start+"\t Stop:"+end); Date date_1 = ms_SDF.parse(start); Date date_2 = ms_SDF.parse(end); Interval interval = new org.joda.time.Interval( date_1.getTime(), date_2.getTime() ); Period period = interval.toPeriod(); //org.joda.time.Period System.out.format("%dY/%dM/%dD, %02d:%02d:%02d.%04d \n", period.getYears(), period.getMonths(), period.getDays(), period.getHours(), period.getMinutes(), period.getSeconds(), period.getMillis()); }
Java 8使用即时和持续时间
Instant start = Instant.now(); Thread.sleep(5000); Instant end = Instant.now(); System.out.println(Duration.between(start, end));
我们也可以使用Apache公共类的StopWatch类来测量时间。
示例代码
org.apache.commons.lang.time.StopWatch sw = new org.apache.commons.lang.time.StopWatch(); System.out.println("getEventFilterTreeData :: Start Time : " + sw.getTime()); sw.start(); // Method execution code sw.stop(); System.out.println("getEventFilterTreeData :: End Time : " + sw.getTime());
在Java 8中,你也可以用一些常规的方法来做这样的事情:
Object returnValue = TimeIt.printTime(() -> methodeWithReturnValue()); //do stuff with your returnValue
与TimeIt一样:
public class TimeIt { public static <T> T printTime(Callable<T> task) { T call = null; try { long startTime = System.currentTimeMillis(); call = task.call(); System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s"); } catch (Exception e) { //... } return call; } }
使用这种方法,您可以轻松地在代码中的任何地方进行时间测量,而不会破坏它。 在这个简单的例子中,我只是打印时间。 你可以添加一个SwitchIt的TimeIt,例如只打印DebugMode或其他东西的时间。
如果你正在使用函数,你可以做这样的事情:
Function<Integer, Integer> yourFunction= (n) -> { return IntStream.range(0, n).reduce(0, (a, b) -> a + b); }; Integer returnValue = TimeIt.printTime2(yourFunction).apply(10000); //do stuff with your returnValue public static <T, R> Function<T, R> printTime2(Function<T, R> task) { return (t) -> { long startTime = System.currentTimeMillis(); R apply = task.apply(t); System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s"); return apply; }; }
我们正在使用AspectJ和Java注释来达到这个目的。 如果我们需要知道一个方法的执行时间,我们简单地注释它。 更高级的版本可以使用自己的日志级别,可以在运行时启用和禁用。
public @interface Trace { boolean showParameters(); } @Aspect public class TraceAspect { [...] @Around("tracePointcut() && @annotation(trace) && !within(TraceAspect)") public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) { Object result; // initilize timer try { result = jp.procced(); } finally { // calculate execution time } return result; } [...] }
只是一个小小的转折,如果你不使用工具,并想要执行时间较less的方法:执行多次,每次执行次数加倍,直到达到一秒钟左右。 因此,调用System.nanoTime等等的时间,以及System.nanoTime的准确性都不会影响结果。
int runs = 0, runsPerRound = 10; long begin = System.nanoTime(), end; do { for (int i=0; i<runsPerRound; ++i) timedMethod(); end = System.nanoTime(); runs += runsPerRound; runsPerRound *= 2; } while (runs < Integer.MAX_VALUE / 2 && 1000000000L > end - begin); System.out.println("Time for timedMethod() is " + 0.000000001 * (end-begin) / runs + " seconds");
当然,关于使用挂钟的注意事项适用于:JIT编译,multithreading/进程等的影响。因此,您需要先执行该方法很多次,以便JIT编译器完成工作,然后重复这个testing多次,并采取最低的执行时间。
真的很好的代码。
http://www.rgagnon.com/javadetails/java-0585.html
import java.util.concurrent.TimeUnit; long startTime = System.currentTimeMillis(); ........ ........ ........ long finishTime = System.currentTimeMillis(); String diff = millisToShortDHMS(finishTime - startTime); /** * converts time (in milliseconds) to human-readable format * "<dd:>hh:mm:ss" */ public static String millisToShortDHMS(long duration) { String res = ""; long days = TimeUnit.MILLISECONDS.toDays(duration); long hours = TimeUnit.MILLISECONDS.toHours(duration) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)); long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)); if (days == 0) { res = String.format("%02d:%02d:%02d", hours, minutes, seconds); } else { res = String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds); } return res; }
new Timer(""){{ // code to time }}.timeMe(); public class Timer { private final String timerName; private long started; public Timer(String timerName) { this.timerName = timerName; this.started = System.currentTimeMillis(); } public void timeMe() { System.out.println( String.format("Execution of '%s' takes %dms.", timerName, started-System.currentTimeMillis())); } }
你可以使用Perf4j 。 非常酷的工具。 用法很简单
String watchTag = "target.SomeMethod"; StopWatch stopWatch = new LoggingStopWatch(watchTag); Result result = null; // Result is a type of a return value of a method try { result = target.SomeMethod(); stopWatch.stop(watchTag + ".success"); } catch (Exception e) { stopWatch.stop(watchTag + ".fail", "Exception was " + e); throw e; }
更多信息可以在开发者指南中find
编辑: 项目似乎死了
JEP 230:Microbenchmark Suite
仅供参考, JEP 230:Microbenchmark Suite是OpenJDK提议:
在JDK源代码中添加基本的microbenchmarks套件,使开发人员可以轻松运行现有的微基准并创build新的基准。
这个提议并没有削减Java 9,但可能会在稍后添加。
Java Microbenchmark Harness(JMH)
同时,您可能需要查看提案所基于的Java Microbenchmark Harness(JMH)项目。
我基本上做了这种变化,但考虑热点编译如何工作,如果你想得到准确的结果,你需要扔掉头几个测量,并确保你在现实世界(阅读应用程序特定)的应用程序中使用的方法。
如果JIT决定编译它,你的数字将会有很大的变化。 所以请注意
有几种方法可以做到这一点。 我通常会回到使用这样的东西:
long start = System.currentTimeMillis(); // ... do something ... long end = System.currentTimeMillis();
或与System.nanoTime()相同的东西;
对于事情的基准方面更多的东西似乎也有这个: http : //jetm.void.fm/从来没有尝试过。
使用jcabi方面的 AOP / AspectJ和@Loggable
注释可以简化和@Loggable
:
@Loggable(Loggable.DEBUG) public String getSomeResult() { // return some value }
每个调用这个方法都会被发送到SLF4J日志logging工具,并且具有DEBUG
日志级别。 每条日志消息都会包含执行时间。
如果你想挂钟时间
long start_time = System.currentTimeMillis(); object.method(); long end_time = System.currentTimeMillis(); long execution_time = end_time - start_time;
正如“skaffman”所说,使用AOP或者你可以使用运行时字节码编织,就像unit testing方法的覆盖工具使用透明地添加计时信息到被调用的方法。
您可以查看像Emma这样的开源工具工具所使用的代码( emma/emma-2.0.5312-src.html )。 其他开源覆盖工具是cobertura/cobertura-1.9-src.html 。
如果你最终设法做你的设置,请。 与您的ant任务/jar子在这里与社区分享。
long startTime = System.currentTimeMillis(); // code goes here long finishTime = System.currentTimeMillis(); long elapsedTime = finishTime - startTime; // elapsed time in milliseconds
我修改了正确答案的代码,以秒为单位得到结果:
long startTime = System.nanoTime(); methodCode ... long endTime = System.nanoTime(); double duration = (double)(endTime - startTime) / (Math.pow(10, 9)); Log.v(TAG, "MethodName time (s) = " + duration);
Spring根据JavaDoc提供了一个实用工具类org.springframework.util.StopWatch :
简单的秒表,允许多个任务的计时,显示每个指定任务的总运行时间和运行时间。
用法:
StopWatch stopWatch = new StopWatch("Performance Test Result"); stopWatch.start("Method 1"); doSomething1();//method to test stopWatch.stop(); stopWatch.start("Method 2"); doSomething2();//method to test stopWatch.stop(); System.out.println(stopWatch.prettyPrint());
输出:
StopWatch 'Performance Test Result': running time (millis) = 12829 ----------------------------------------- ms % Task name ----------------------------------------- 11907 036% Method 1 00922 064% Method 2
方面:
@Around("execution(* my.package..*.*(..))") public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable { StopWatch stopWatch = new StopWatch(); stopWatch.start(); Object retVal = joinPoint.proceed(); stopWatch.stop(); log.info(" execution time: " + stopWatch.getTotalTimeMillis() + " ms"); return retVal; }
只要想知道时间,你可以试试这个方法。
long startTime = System.currentTimeMillis(); //@ Method call System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));
好的,这是一个简单的类,用于简单的函数定时。 下面有一个例子。
public class Stopwatch { static long startTime; static long splitTime; static long endTime; public Stopwatch() { start(); } public void start() { startTime = System.currentTimeMillis(); splitTime = System.currentTimeMillis(); endTime = System.currentTimeMillis(); } public void split() { split(""); } public void split(String tag) { endTime = System.currentTimeMillis(); System.out.println("Split time for [" + tag + "]: " + (endTime - splitTime) + " ms"); splitTime = endTime; } public void end() { end(""); } public void end(String tag) { endTime = System.currentTimeMillis(); System.out.println("Final time for [" + tag + "]: " + (endTime - startTime) + " ms"); } }
使用示例:
public static Schedule getSchedule(Activity activity_context) { String scheduleJson = null; Schedule schedule = null; /*->*/ Stopwatch stopwatch = new Stopwatch(); InputStream scheduleJsonInputStream = activity_context.getResources().openRawResource(R.raw.skating_times); /*->*/ stopwatch.split("open raw resource"); scheduleJson = FileToString.convertStreamToString(scheduleJsonInputStream); /*->*/ stopwatch.split("file to string"); schedule = new Gson().fromJson(scheduleJson, Schedule.class); /*->*/ stopwatch.split("parse Json"); /*->*/ stopwatch.end("Method getSchedule"); return schedule; }
控制台输出示例:
Split time for [file to string]: 672 ms Split time for [parse Json]: 893 ms Final time for [get Schedule]: 1565 ms
System.nanoTime()
是一个非常精确的系统实用程序来衡量执行时间。 但要小心,如果您在预先调度模式(默认)下运行,此实用程序实际上测量挂钟时间,而不是CPU时间。 因此,根据系统负载,您可能会注意到从运行到运行的不同执行时间值。 如果你寻找CPU时间,我认为在实时模式下运行你的程序将有所斩获。 你必须使用RT linux。 链接: 使用Linux进行实时编程
我的机器上的性能测量
- System.nanoTime():750ns
- System.currentTimeMillis():18ns
如前所述,System.nanoTime()被认为是测量经过的时间。 只要知道如果使用insied循环或类似的成本。
如果java有更好的function支持,这样会很好,所以需要测量的动作可以被包装成一个块:
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中,引入了一个名为Instant
的新类。 根据文档:
即时表示时间线上的纳秒开始。 这个类对于生成表示机器时间的时间戳很有用。 瞬间的范围需要存储大于一长的数字。 为了达到这个目的,这个类存储了一个long代表epoch-seconds和一个代表纳秒级的int,它总是在0到999,999,999之间。 历元秒是从1970-01-01T00:00:00Z的标准Java时期开始测量的,其中纪元之后的瞬间具有正值,而较早的时刻具有负值。 对于历元时间和纳秒时间部分,时间线上的值总是比较小的值更大。
这可以用作:
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
。