日常编码中,如果想对某一段程序计时,应该怎么做呢?比较简单粗暴的办法就是开始和结束各自取当前时间戳.
代码语言:javascript复制 long start = System.currentTimeMillis();
dosomething();
System.out.println("做了一些事情:" (System.currentTimeMillis() - start));
其实看起来还好对不对,我偶尔这么用一下也觉得还好,知道某一次维护某一份代码.
前任因为需要对程序的性能做一些优化,所以要找到程序耗时较高的部分,所以几个主要的类里面到处是这种代码,在他进行优化完毕之后并没有进行删除.
而我当时程序已经运行良好了,需要进行代码clean(因为实在是太丑了),一个个删除实在是累skr人.
而且long start = System.currentTimeMillis();
这一句实在是不好找,因为他没有引用别的参数,所以并不会有编译器来提醒我哪里还有遗漏的,导致在那之后好久都会偶尔又找到一条呢!
而我在日常写一些奇怪的类的时候,也有打印耗时的需求,比如我前面一些博客里面,说怎么操作优化了效率,总不能空口白话,因此也需要经常的打印程序耗时.我感觉到上面的这种粗暴的办法太傻了,但是也没想到什么好办法,知道看到了Ticker
类.
这个类的实现功能是,可以对程序分段计时并标注,并且将代码封装起来,尽量少的侵入业务代码,同时最后以较好的可读性打印出来.
实现方法,维护一个<string,long>的list,注意前面这么写只是代表了一个对象,而不是一个Map.用户每次手动调用计时的时候,计算与前一次计时之间的间隔时间,将其保存起来,同时,Ticker
保存初始化的时间,以及最终调用toString
的时间,因此你可以很清楚的看到一个类似于:
thing1: 10ms
thing2: 20ms
total: 30ms
这样子的输出.
下面是类的代码以及使用示例:
代码语言:javascript复制package util;
import java.util.ArrayList;
import java.util.List;
public class Ticker {
private final List<T> tags = new ArrayList<>(2);
private final long start;
private long last;
private long end;
public Ticker() {
start = System.currentTimeMillis();
last = start;
}
public void tack() {
last = System.currentTimeMillis();
}
public void tick(String tag) {
long now = System.currentTimeMillis();
tags.add(new T(tag, (int) (now - last)));
last = now;
}
public int total() {
if (end == 0)
end = System.currentTimeMillis();
return (int) (end - start);
}
public long getBegin() {
return start;
}
@Override
public String toString() {
return summary();
}
private String summary() {
end = System.currentTimeMillis();
StringBuilder sb = new StringBuilder(32);
for (T tag : tags) {
sb.append(tag.tag).append(" ").append(tag.since).append("ms, ");
}
sb.append("total ");
if ((end - start) < 10000) {
sb.append(end - start).append("ms");
} else {
sb.append((end - start) / 1000).append("s");
}
return sb.toString();
}
static class T {
final String tag;
final int since;
T(String tag, int since) {
this.tag = tag;
this.since = since;
}
}
private static void db() throws InterruptedException {
Thread.sleep(1000);
}
private static void col() {
for (int i = 0; i < 10000; i) {
int j = i;
}
}
public static void main(String[] args) throws InterruptedException {
Ticker ticker = new Ticker();
db();
ticker.tick("db");
col();
ticker.tick("col");
System.out.println(ticker.toString());
}
}
main方法中的测试代码输出:
代码语言:javascript复制db 1005ms, col 1ms, total 1006ms
是不是感觉好很多了呢.
完全没有什么依赖,没有什么副作用,copy到项目里就能用,眼睛舒服了许多.
完。
ChangeLog
2019-04-28 完成
以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
联系邮箱:huyanshi2580@gmail.com