如何在Java中以微秒精度测量时间?

时间:2009-02-02 16:49:06

标签: java time

我在互联网上看到我应该使用System.nanoTime(),但这对我不起作用 - 它给我的时间精确到毫秒。我只需要在我的函数执行之前和之后的微秒,这样我就知道需要多长时间。我正在使用Windows XP。

基本上,我有这样的代码,例如,在java链表中进行了100万到1000万次插入。问题是我无法衡量精确度;有时在较小的列表中插入所有内容所需的时间较短。

以下是一个例子:

class test
{
    public static void main(String args[])
    {
        for(int k=1000000; k<=10000000; k+=1000000)
        {
            System.out.println(k);
            LinkedList<Integer> aux = new LinkedList<Integer>();
            //need something here to see the start time
            for(int i=0; i<k; i++)
                aux.addFirst(10000);
            //need something here to see the end time
            //print here the difference between both times
        }
    }
}

我做了很多次 - 每个k都有一个外部循环做20次 - 但结果并不好。有时需要更少的时间来进行1000万次插入而不是100万次插入,因为我现在没有使用我现在使用的正确测量时间(System.nanoTime())

编辑2:是的,我正在使用Sun JVM。

编辑3:我可能在代码中做错了,我会看到改变它是否符合我的要求。

编辑4:我的错误,似乎System.nanoTime()有效。呼。

12 个答案:

答案 0 :(得分:30)

我的猜测是,因为System.nanoTime()使用“最精确的可用系统计时器”,它显然只有毫秒级的系统精度,所以你无法获得更好的效果。

答案 1 :(得分:25)

我不清楚你究竟在做什么基准测试,但总的来说,任何使这样运行时间短,测试精度低于50毫秒的测试都是相关的非常容易受到其他干扰。

我通常会尝试使基准测试运行至少10秒。我正在编写的框架将猜测要运行多少次迭代,这将需要30秒。这意味着你不会因为某些其他进程偷走CPU几毫秒而不会得到从根本上不同的结果。

运行时间越长几乎总是一种更好的方法,而不是尝试以更精细的方式进行测量。

答案 2 :(得分:4)

System.nanoTime()在CPU中使用计数器,在Windows XP和Linux上通常精确到1微秒左右。

注意:Windows XP在多CPU机器上通常不太准确,因为它不能补偿具有不同计数器的不同CPU。 Linux确实如此。 注2:它会相对于System.currentTimeMillis()漂移,因为它基于CPU的时钟精度(在一段时间内不需要如此准确),而不是你的时钟获得时间。(每天漂移较少,但粒度较小)

在您的基准测试中,您基本上是在测试创建新对象的速度。毫不奇怪,根据您的GC设置以及最近GC的执行情况,您的结果会有很大差异。

尝试使用以下选项运行测试,您会看到非常不同的结果。

-verbosegc -XX:NewSize=128m -mx256m

答案 3 :(得分:3)

这很奇怪。 System.nanoTime()应该可以工作。您使用的是Sun JVM吗?

你可以重复你的操作1000次并将时间除以1000来找出你需要知道的内容吗?

答案 4 :(得分:3)

你必须重复测试数千次。有很多事情会影响您的测量,例如垃圾收集,I / O,交换/输出,就绪队列线程的大小等。

答案 5 :(得分:3)

如果您想获得可靠的结果,请使用分析器。我建议VisualVM,它易于安装,并且从版本1.6.0_07开始与JDK捆绑在一起。

这是一个易于使用的可视化工具,它集成了多个命令行JDK工具和轻量级分析功能。

答案 6 :(得分:3)

使用java.time

仅供参考,Java 9及更高版本具有Clock的全新实现,可以以高达纳秒的分辨率捕获当前时刻。

Instant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

致电Instant.now以捕捉当前时刻。

  • 在Java 9及更高版本中,您获得当前时刻最高nanoseconds的分辨率。
  • 在Java 8中,当前时刻仅被捕获到milliseconds分辨率(您确实保持值为纳秒,但只有捕获以毫秒为单位的当前时刻)。

    即时瞬间= Instant.now();

使用Duration类表示未附加到时间轴的时间跨度。以秒和纳秒为单位保留一定的时间。

Duration d = Duration.between( instantThen , Instant.now() );

要明确的是,问题中提出的microseconds分辨率介于毫秒和纳秒的粒度之间。小数位数:millis为3(0.123),micros为6(0.123456),nanos为9(0.123456789)。

买者

Java依赖于计算机的硬件时钟。正如其他人警告的那样,硬件几乎肯定会以远低于准确度远远低于纳秒的分辨率来捕获时间。

如此精细的基准测试通常会出现问题并且不可取

谨防premature optimization

有人建议在JEP 230: Microbenchmark Suite中向Java平台添加微基准测试工具。基于Java Microbenchmark Harness (JMH)

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 7 :(得分:1)

可能是基础操作系统不能提供具有纳秒级精度的计时器。

还有older post

答案 8 :(得分:1)

是的,System.nanoTime的准确性和精确度通常比System.currentTimeMillis好得多,但是没有保证:在最坏的情况下它会变得同样糟糕。

ThreadMXBean.getCurrentThreadCpuTime往往会产生更小的时间,但它的分辨率不明确,而且它还有其他缺点(你真的想要你的平台支持CPU时间吗?,平台相关的语义吗?)。

用所有三种技术测量时间也有一些成本,即需要时间本身,这会使测量失真。成本高度依赖于平台,但通常是成本(System.currentTimeMillis)&lt;&lt; cost(System.nanoTime)&lt;&lt;成本(ThreadMXBean.getCurrentThreadCpuTime)。

关于一般的微基准测试,请参阅

答案 9 :(得分:0)

依赖于短时间间隔的这种基准会给您带来不可靠的结果。由于I / O,交换,进程交换,缓存,垃圾收集等外部因素,您总会得到不同的结果。此外,JVM会优化您的调用,因此第一次测量的事情可能比以后的调用慢。 JVM越来越多地优化您执行的命令。

此外,像System.nanoTime()这样的方法依赖于底层系统的计时器。他们可能(并且很可能)不具有以该准确度来衡量的粒度。引用API

  

此方法提供纳秒级   精确,但不一定   纳秒精度。没有保证   关于价值的频率   变化

要真正高精度测量,您需要访问具有保证精度的外部定时硬件。

为了使您的基准更加稳定,您需要多次执行它并测量比毫秒更长的时间间隔。

答案 10 :(得分:0)

快速而又肮脏的#34;我最终选择的解决方案:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

更新:

我最初使用的是System.nanoTime,但之后我发现它应该仅用于已用时间,我最终将代码更改为使用毫秒或在某些地方使用:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

但这只会在值的末尾添加零(micros = millis * 1000)

将此答案留在此处作为&#34;警告标志&#34;以防其他人想到nanoTime:)

答案 11 :(得分:0)

对于我们最近的分析,我发现>>> print("[('aaaa', 34)]") [('aaaa', 34)] >>> >>> print([('aaaa', 34)]) [('aaaa', 34)] 和选项ThreadMXBean.getCurrentThreadCpuTime()完成了我们需要的工作。

有关详细信息,请参阅http://bugs.java.com/view_bug.do?bug_id=6888526