[英]How do I time a method's execution in Java?
Timer
实用程序类用于计时任务需要多长时间等?谷歌上的大多数搜索都会返回调度线程和任务的计时器的结果,这不是我想要的。
总是有老式的方法:
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() 做的更好。 两者都有一些限制(操作系统调度切片等),但效果很好。
几次运行的平均值(越多越好),你会得到一个不错的主意。
来吧伙计们! 没有人提到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+
将所有可能的方式聚集到一个地方。
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 ) );
人类可读格式
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 « 秒表的一个目的是以纳秒为单位测量经过的时间。
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 Lang JAR « 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()) );
乔达时间
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 中的 Java 日期时间 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]
使用分析器(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;
}
}
使用 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;
}
}
使用此方法,您可以在代码中的任何位置轻松测量时间而不会破坏它。 在这个简单的例子中,我只是打印时间。 您可以为 TimeIt 添加一个开关,例如仅在 DebugMode 或其他东西中打印时间。
如果你正在使用Function你可以做这样的事情:
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());
仅供参考, JEP 230:Microbenchmark Suite是一个OpenJDK项目,用于:
在 JDK 源代码中添加一套基本的微基准测试,让开发人员可以轻松地运行现有微基准测试并创建新的微基准测试。
此功能在Java 12 中出现。
对于 Java 的早期版本,请查看 JEP 230 所基于的Java Microbenchmark Harness (JMH)项目。
如果您不使用工具并希望对执行时间较短的方法进行计时,请稍作改动:执行多次,每次将执行次数加倍,直到达到一秒左右。 因此,调用 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编译,多线程/进程等的影响,因此,你需要先执行该方法的很多次第一,使得JIT编译器的工作,然后多次重复此测试并使用最短的执行时间。
为此,我们使用了 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;
}
[...]
}
真的很好的代码。
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;
}
您可以使用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;
}
更多信息可以在开发者指南中找到
编辑:项目似乎死了
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;
}
我已经编写了一个方法来以一种更易读的形式打印方法执行时间。 例如,要计算 1 百万的阶乘,大约需要 9 分钟。 所以执行时间打印为:
Execution Time: 9 Minutes, 36 Seconds, 237 MicroSeconds, 806193 NanoSeconds
代码在这里:
public class series
{
public static void main(String[] args)
{
long startTime = System.nanoTime();
long n = 10_00_000;
printFactorial(n);
long endTime = System.nanoTime();
printExecutionTime(startTime, endTime);
}
public static void printExecutionTime(long startTime, long endTime)
{
long time_ns = endTime - startTime;
long time_ms = TimeUnit.NANOSECONDS.toMillis(time_ns);
long time_sec = TimeUnit.NANOSECONDS.toSeconds(time_ns);
long time_min = TimeUnit.NANOSECONDS.toMinutes(time_ns);
long time_hour = TimeUnit.NANOSECONDS.toHours(time_ns);
System.out.print("\nExecution Time: ");
if(time_hour > 0)
System.out.print(time_hour + " Hours, ");
if(time_min > 0)
System.out.print(time_min % 60 + " Minutes, ");
if(time_sec > 0)
System.out.print(time_sec % 60 + " Seconds, ");
if(time_ms > 0)
System.out.print(time_ms % 1E+3 + " MicroSeconds, ");
if(time_ns > 0)
System.out.print(time_ns % 1E+6 + " NanoSeconds");
}
}
使用来自jcabi-aspects 的AOP/AspectJ 和@Loggable
注释,您可以轻松紧凑地完成:
@Loggable(Loggable.DEBUG)
public String getSomeResult() {
// return some value
}
对此方法的每次调用都将发送到具有DEBUG
日志级别的 SLF4J 日志记录工具。 每条日志消息都将包含执行时间。
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()));
}
}
我基本上做了这种变化,但考虑到热点编译的工作原理,如果您想获得准确的结果,您需要放弃前几次测量并确保您在现实世界(阅读特定于应用程序)应用程序中使用该方法。
如果 JIT 决定编译它,您的数字将有很大差异。 所以请注意
有几种方法可以做到这一点。 我通常会回退到只使用这样的东西:
long start = System.currentTimeMillis();
// ... do something ...
long end = System.currentTimeMillis();
或与 System.nanoTime() 相同;
对于基准测试方面的更多内容,似乎还有这个: http : //jetm.void.fm/虽然从未尝试过。
如果你想要挂钟时间
long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;
您可以使用提供各种测量工具的Metrics库。 添加依赖:
<dependencies>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
</dependency>
</dependencies>
并为您的环境配置它。
方法可以用@Timed注释:
@Timed
public void exampleMethod(){
// some code
}
或用Timer包裹的一段代码:
final Timer timer = metricsRegistry.timer("some_name");
final Timer.Context context = timer.time();
// timed code
context.stop();
聚合指标可以导出到控制台、JMX、CSV 或其他。
@Timed
指标输出示例:
com.example.ExampleService.exampleMethod
count = 2
mean rate = 3.11 calls/minute
1-minute rate = 0.96 calls/minute
5-minute rate = 0.20 calls/minute
15-minute rate = 0.07 calls/minute
min = 17.01 milliseconds
max = 1006.68 milliseconds
mean = 511.84 milliseconds
stddev = 699.80 milliseconds
median = 511.84 milliseconds
75% <= 1006.68 milliseconds
95% <= 1006.68 milliseconds
98% <= 1006.68 milliseconds
99% <= 1006.68 milliseconds
99.9% <= 1006.68 milliseconds
long startTime = System.currentTimeMillis();
// code goes here
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime; // elapsed time in milliseconds
正如“skaffman”所说,使用 AOP 或者您可以使用运行时字节码编织,就像单元测试方法覆盖工具用来透明地向调用的方法添加计时信息一样。
您可以查看 Emma 等开源工具工具使用的代码( http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0 )。 另一个开源覆盖工具是http://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download 。
如果你最终设法做你设定的,请。 在这里与您的 ant 任务/罐子与社区分享它。
我修改了正确答案中的代码以在几秒钟内获得结果:
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);
好的,这是一个简单的类,用于对您的函数进行简单的计时。 下面有一个例子。
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
您可以使用 spring 核心项目中的秒表类:
代码:
StopWatch stopWatch = new StopWatch()
stopWatch.start(); //start stopwatch
// write your function or line of code.
stopWatch.stop(); //stop stopwatch
stopWatch.getTotalTimeMillis() ; ///get total time
秒表文档:简单的秒表,允许对多个任务进行计时,显示每个命名任务的总运行时间和运行时间。 隐藏 System.currentTimeMillis() 的使用,提高应用程序代码的可读性并减少计算错误的可能性。 请注意,此对象并非设计为线程安全的,也不使用同步。 此类通常用于在概念验证和开发期间验证性能,而不是作为生产应用程序的一部分。
如果只是想知道时间,您可以尝试这种方式。
long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));
我的机器上的性能测量
System.nanoTime() : 750ns
System.currentTimeMillis() : 18ns
如前所述, System.nanoTime()
被认为可以测量经过的时间。 如果在循环等内使用,请注意成本。
在 Java 8 中引入了一个名为Instant
的新类。 根据文档:
Instant 表示时间线上一纳秒的开始。 此类可用于生成时间戳以表示机器时间。 瞬间的范围需要存储一个大于 long 的数字。 为了实现这一点,该类存储了一个表示纪元秒的 long 和一个表示纳秒秒的 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
。
在 Spring 框架中,我们有一个叫做 StopWatch (org.springframework.util.StopWatch) 的调用
//measuring elapsed time using Spring StopWatch
StopWatch watch = new StopWatch();
watch.start();
for(int i=0; i< 1000; i++){
Object obj = new Object();
}
watch.stop();
System.out.println("Total execution time to create 1000 objects in Java using StopWatch in millis: "
+ watch.getTotalTimeMillis());
如果 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);
}
}
}
你可以使用javaagent来修改java类字节,动态添加监控代码。github上有一些开源工具可以为你做到这一点。
如果你想自己做,只需实现javaagent ,使用javassist修改你要监控的方法,以及方法返回之前的监控代码。它很干净,你甚至可以监控你没有源代码的系统.
这是漂亮的打印字符串准备好格式化的秒数,类似于 google 搜索时间进行搜索:
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)
我实现了一个简单的计时器,我认为它非常有用:
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.");
System.nanoTime()
是一个非常精确的系统实用程序,用于测量执行时间。 但请注意,如果您在抢占式调度程序模式(默认)下运行,该实用程序实际上测量的是挂钟时间而不是 CPU 时间。 因此,您可能会注意到不同的运行时间值,具体取决于系统负载。 如果您寻找 CPU 时间,我认为以实时模式运行您的程序会解决问题。 你必须使用RT linux。 链接: 使用 Linux 进行实时编程
在 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) { ...
我希望这会有所帮助。
对于 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;
}
也可以实现 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);
这里有很多有效的答案,所有这些都在方法中实现。 为了制作一个通用的计时方法,我通常有一个由以下内容组成的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);
}
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();
纯 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;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.