如何计时Java程序的执行速度


85

您如何安排Java程序的执行时间?我不确定应该使用哪个类来执行此操作。

我正在寻找类似的东西:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);

Answers:


139
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));

2
它实际上应该实际上是nanoTime
Eugene

6
不应该是nanoTime。请参阅rhu的答案。
fabspro

4
您在此处使用“最终”有什么特殊原因吗?如果您删除该关键字,会有什么不同?
dijxtra

9
@dijxtra使用final具有您不会意外分配给它的优点(以及其他优点,例如匿名类访问等)。在这段代码中,它没有任何区别。制作所有内容final并仅在final需要时将其统一是一种相当普遍的做法。
wchargin

1
要测试的代码以及时间测量值应该多次运行,并且第一个结果应该被丢弃。第一个可能包括类的加载时间等。通过多次运行它,您当然也会获得一个平均数,该平均数会更有用和更可靠。
阿伦·拉玛克里希南

34

请注意,存在一些问题,System#nanoTime()无法可靠地在多核CPU上使用它来记录经过的时间...每个核都有自己的TSC(时间戳计数器):该计数器用于获取纳秒级时间(实际上是自CPU引导以来的滴答数)。

因此,除非操作系统进行一些TSC时间扭曲以保持内核同步,否则如果在获取初始时间读数时线程在一个内核上进行了调度,然后切换到另一个内核,则相对时间可能会偶尔出现向后跳和转发。

我前一段时间在AMD / Solaris上观察到这一点,其中两个时间点之间的经过时间有时以负值或意外大的正数返回。强制使用AMD PowerNow!需要一个Solaris内核补丁和一个BIOS设置。关闭,这似乎解决了它。

此外,System#nanoTime()在VirtualBox环境中使用Java时,还存在(AFAIK)迄今为止尚未修复的错误;由于大多数java.util.concurrency程序包都依赖于nano时间,因此给我们造成了各种奇怪的间歇线程问题。

也可以看看:

System.nanoTime()完全没用吗? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html


9

您获得当前系统时间(以毫秒为单位):

final long startTime = System.currentTimeMillis();

然后,您将要做的事情是:

for (int i = 0; i < length; i++) {
  // Do something
}

然后,您会看到花费了多长时间:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;

BalusC的答案也是正确的。它取决于所需的计时器分辨率以及为什么需要计时。
乔纳森·芬伯格

9

您可以利用System#nanoTime()。在执行之前和之后获取它,然后做一下数学运算即可。上面System#currentTimeMillis()是首选,因为它具有更好的精度。视所使用的硬件和平台而定,否则,您可能会花费不正确的时间间隔。在Windows上使用Core2Duo时,大约在0到15ms之间,实际上什么也无法计算。

一个更高级的工具是探查器


Windows上的计时器默认情况下没有特别好的分辨率。这里一个高性能的计时器也一样,但它是更难从C甚至使用与Java不(据我所知)提供对低两轮牛车的没有JNI的水平咚。
Donal Fellows 2010年

1
nanoTime()有一个问题(至少在Windows上);时间戳特定于处理器内核。我有一个程序的执行时间为负数,因为它在一个内核上具有“开始”时间戳,而在另一个内核上具有“停止”时间戳。
gustafc 2010年

3

对于简单的东西,System.currentTimeMillis()可以工作。

实际上,设置我的IDE非常普遍,因此在输入“ t0”时会生成以下行:

final long t0 = System.currentTimeMillis()

但是对于更复杂的事情,您可能需要使用统计时间度量,例如此处(向下滚动一下,查看表示的时间度量,包括标准偏差等):

http://perf4j.codehaus.org/devguide.html


+1指出自动生成器代码。我一直在使用类似的语句,并且对插入代码模板一无所知。刚刚发现了如何用Eclipse做到这一点,肯定会有所帮助!
杰森

所有Codehaus服务均已终止。您的链接现在已断开。
naXa

2

使用AOP / AspectJ和@Loggable来自jcabi-aspects的注释,您可以轻松而紧凑地完成它:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

对该方法的每次调用都将被发送到具有DEBUG日志记录级别的SLF4J日志记录设备。并且每个日志消息都将包含执行时间。


2

以下是一些在Java中查找执行时间的方法:

1)System.nanoTime()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2)System.currentTimeMillis()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3)Instant.now()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

要么

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4)Date.getTime()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

1

startTime=System.currentTimeMillis()在循环的顶部使用很长的启动时间

放在long endTime= System.currentTimeMillis();循环的末尾。您必须减去这些值才能获得运行时间(以毫秒为单位)。

如果您想要时间以纳秒为单位,请查看 System.nanoTime()


1

我创建了一个更高阶的函数,该函数接受您要在/作为lambda度量的代码:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

这样称呼它:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

输出:

代码0:180528 ns
代码1:12003 ns

特别感谢Andy Turner帮助我减少了冗余。看这里



0

您也可以尝试Perf4J。它是您要寻找的东西的一种整洁的方式,并且可以帮助您在设定的时间范围内汇总性能统计数据,例如平均值,最小值,最大值,标准差和每秒的事务数。来自http://perf4j.codehaus.org/devguide.html的摘录:

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

输出:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]

0
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}

0

使用System.currentTimeMillis()是执行此操作的正确方法。但是,如果您使用命令行,并且想要大致快速地对整个程序进行计时,请考虑:

time java App

这样您就无需修改代码,也不会为应用计时。


这取决于您如何运行代码。如果这是运行服务器的一段代码,那么您将包括错误的启动时间。
阿伦·拉玛克里希南
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.