- 如何获取方法的执行时间?
- 是否有一个
Timer
实用程序类来计算任务所需的时间等?
大多数在Google上搜索的结果都是关于调度线程和任务的定时器,这不是我想要的。
Timer
实用程序类来计算任务所需的时间等?大多数在Google上搜索的结果都是关于调度线程和任务的定时器,这不是我想要的。
总有一种老派的方式:
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()可以得到更好的结果。两者都存在一些限制(比如操作系统调度时间片等),但这个方法效果非常棒。
多次运行后取平均值(运行次数越多越好),你就能得到一个不错的结果。
nanoTime
保证_至少_与currentTimeMillis
一样精确。http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime%28%29 - arkoncurrentTimeMillis
的一个小优点是它是一个实际的时间戳,可以用来记录开始/结束时间,而 nanoTime
"只能用于测量经过的时间,与任何系统或挂钟时间的概念无关。" - Brad ParksSystem.nanoTime()
是专门设计用于测量经过的时间,并且保证不会向前或向后跳动。尽管如此,它通常是负数。因此,您始终需要计算两个时间之间的差值才能得到有效的持续时间。 - Charlie Reitzel加油,大家!没有人提到使用Guava的做法(这种方法可能是很棒的):
Guava 的做法:
import com.google.common.base.Stopwatch;
Stopwatch timer = Stopwatch.createStarted();
//method invocation
LOG.info("Method took: " + timer.stop());
很好的一点是,Stopwatch.toString() 很好地选择了时间单位来进行测量。例如,如果值很小,它会输出 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 或更高版本
start()
(stop()
同理)。 - Mingwei SamuelSystem.nanoTime()
的封装,所以+1。 - Charlie ReitzelDuration.between(start, end).getSeconds()
。Duration
还有其他方法可以将时间单位转换为毫秒,例如 toMillis()
。 - Emil Lunde将所有可能的方式汇集到一个地方。
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);
System.currentTimeMillis()
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 ) );
易读的格式
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;
}
Guava: Google秒表JAR « Stopwatch对象的目的是测量经过的时间,单位为纳秒。
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);
Apache Commons LangJAR « StopWatch 提供了一个方便的API用于计时。
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()) );
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中的日期时间API:Duration对象表示两个Instant对象之间的时间段。
Instant start = java.time.Instant.now();
Thread.sleep(1000);
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.println( between ); // PT1.001S
System.out.format("%dD, %02d:%02d:%02d.%04d \n", between.toDays(),
between.toHours(), between.toMinutes(), between.getSeconds(), between.toMillis()); // 0D, 00:00:01.1001
Spring Framework 提供 StopWatch 实用类来测量 Java 中的流逝时间。
StopWatch sw = new org.springframework.util.StopWatch();
sw.start("Method-1"); // Start a named task
Thread.sleep(500);
sw.stop();
sw.start("Method-2");
Thread.sleep(300);
sw.stop();
sw.start("Method-3");
Thread.sleep(200);
sw.stop();
System.out.println("Total time in milliseconds for all tasks :\n"+sw.getTotalTimeMillis());
System.out.println("Table describing all tasks performed :\n"+sw.prettyPrint());
System.out.format("Time taken by the last task : [%s]:[%d]",
sw.getLastTaskName(),sw.getLastTaskTimeMillis());
System.out.println("\n Array of the data for tasks performed « Task Name: Time Taken");
TaskInfo[] listofTasks = sw.getTaskInfo();
for (TaskInfo task : listofTasks) {
System.out.format("[%s]:[%d]\n",
task.getTaskName(), task.getTimeMillis());
}
输出:
Total time in milliseconds for all tasks :
999
Table describing all tasks performed :
StopWatch '': running time (millis) = 999
-----------------------------------------
ms % Task name
-----------------------------------------
00500 050% Method-1
00299 030% Method-2
00200 020% Method-3
Time taken by the last task : [Method-3]:[200]
Array of the data for tasks performed « Task Name: Time Taken
[Method-1]:[500]
[Method-2]:[299]
[Method-3]:[200]
new Date().getTime()
只是一个伪装成System.currentTimeMillis()
的方法。new Date()
和new Date(System.currentTimeMillis())
的作用相同,而getTime()
将返回该long
值(这是该类中唯一未被标记为弃用的功能)。同样,Calendar.getInstance().getTime()
与new Date()
完全相同,但开销更大,因为它会准备此代码片段不使用的东西。 - HolgerCaused by: java.lang.NoSuchMethodError: 'long com.google.common.base.Platform.systemNanoTime()' at com.google.common.base.Ticker$1.read(Ticker.java:60) ~[guava-18.0.jar:?], Stopwatch.start(Stopwatch.java:162) ~[guava-18.0.jar:?], Stopwatch.createStarted(Stopwatch.java:109) ~[guava-18.0.jar:?]
- undefined使用性能分析器(JProfiler、Netbeans Profiler、Visual VM、Eclipse Profiler等)。这样可以获得最准确的结果,同时对系统影响最小。这些分析器都使用内置的JVM机制进行性能分析,还能提供额外的信息,如堆栈跟踪、执行路径等,如果需要的话,还可以获得更全面的结果。
使用完全集成的性能分析器时,对一个方法进行性能分析非常简单。右键单击,选择性能分析器 -> 添加到根方法。然后像运行测试或调试器一样运行分析器即可。
System.currentTimeMillis();
不是衡量算法性能的好方法。它测量的是用户观察计算机屏幕所经历的总时间,其中包括后台运行的其他所有程序消耗的时间。如果您的工作站上有许多程序在运行,这可能会产生很大的差异。
正确的方法是使用 java.lang.management
包。
来自http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking网站(存档链接):
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;
}
}
System.nanoTime()
来计算经过的时间是我认为衡量单线程性能最好的方法。几乎总是可以通过调整每个线程使用的代码并使用较粗糙的方法来测量对整体吞吐量的影响,例如,您可以使用10个线程在1小时内索引50GB,而使用1个线程则只能在1小时内索引10GB或其他任何情况。 - Charlie Reitzel这可能不是你想听到的,但这是AOP的一个很好的用法。在方法周围包装一个代理拦截器,在那里进行计时。
AOP的什么、为什么和如何超出了这个答案的范围,但这是我可能会采取的方式。
编辑:这里有一个链接,可以帮助你开始使用Spring AOP,如果你感兴趣的话。这是我接触过的Java中最易于使用的AOP实现。
此外,考虑到其他人的非常简单的建议,我应该补充说,AOP适用于当你不想让像计时这样的东西侵入你的代码中。但在许多情况下,这种简单易行的方法也是可以的。
使用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;
}
}
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;
};
}
我们还可以使用Apache commons的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());
Instant
类:https://dev59.com/InVC5IYBdhLWcg3wz0h9#30975902 - akhil_mittal