处理时间措施的最佳方法是什么?

时间:2016-05-06 08:40:30

标签: java performance time java-8 timing

我的目标是编写一个测量方法执行或交易时间以及处理测量的框架,即存储,分析等。事务可能包括调用外部系统,同步或异步等待结果。

围绕该主题已经存在一些问题,例如

所有答案都归结为三种方法来消磨时间

  • System.currentTimeMillis()
  • System.nanoTime()
  • Instant.now()Duration(自Java 8起)

我知道,所有这些都有一些影响

System.currentTimeMillis的()

此方法的结果取决于平台。在Linux上你获得1ms的分辨率,在Windows中你获得10ms(单核)~15ms(多核)。因此,可以测量大型运行操作或短期运行操作的多次执行。

System.nanoTime()

你得到一个高分辨率的时间测量,具有纳秒精度(但不一定是纳秒精度),并且在292年之后你会得到溢出(我可以忍受)。

Instant.now()和持续时间

从Java 8开始,有新的时间API。瞬间有第二个和第二个纳米字段,因此它在对象引用的顶部使用两个长值(Duration相同)。您还可以获得纳秒精度,具体取决于基础时钟(请参阅“Java 8 Instant.now() with nanosecond resolution?”)。实例化是通过调用Instant.now()来完成的,System.currentTimeMillis()映射到System.nanoTime()以获得正常的系统时钟。

鉴于事实,很明显,最佳精确度只能通过sed '/define host/ {:a;/}/!{N;ba};/hostname02x/d}' hotname.cfg 实现,但我的问题更多地针对最佳实践来处理一般的措施,不仅包括采取措施,还包括措施处理。

  • Instant和Duration提供最佳的API支持(计算,比较等),但在标准情况下具有os-dependend精度,内存和创建度量的更多开销(对象构造,更深的callstack)

  • System.nanoTime()和System.currentTimeMillis()具有不同的精度级别,但只有基本的“api”支持(数学操作为long),但更快和更小以保留在内存中。 / p>

那么最好的方法是什么?有没有我没想过的含义?还有其他选择吗?

2 个答案:

答案 0 :(得分:5)

你过分关注精度的不重要细节。如果要测量/分析某些操作的执行,则必须确保这些操作运行的时间足够长,以使测量不受一次性工件,线程调度时间,垃圾收集或HotSpot优化的微小差异的影响。在大多数情况下,如果差异小于毫秒级,则从它们得出结论是没有用的。

更重要的方面是这些工具是否专为您的任务而设计。 System.currentTimeMillis()和所有其他基于挂钟的API,无论它们是否基于currentTimeMillis(),都旨在为您提供一个时钟,旨在与地球的旋转及其绕太阳的路径同步,加载它Leap Seconds和其他纠正措施的负担,而不是说你的计算机的时钟可能与挂钟不同,并得到纠正,例如,通过NTP更新,在最糟糕的情况下,当你试图测量你的经过时间时,你可能会向右跳,也许甚至倒退。

相比之下,System.nanoTime()旨在衡量已用时间(正是您想要做的事情)而不是其他任何内容。由于其返回值具有未指定的原点,甚至可能是负数,因此此方法返回的两个值之间只有差异才有意义。您甚至可以在文档中找到它:

  

只有在计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才会有意义。

因此,当您想要测量和处理方法执行或事务的已用时间时,System.nanoTime()是可行的方法。当然,它只提供裸long值,但不清楚您想要什么样的API支持。由于时间点不相关甚至分散注意力,因此您只有一段时间,您可以将其转换为其他time units,或者,如果您想使用新时间API,则可以创建{{1}使用Duration.ofNanos(long)的对象,允许您添加和减去持续时间值并进行比较,但您可以做的更多。你不得将它们与基于挂钟或日历的持续时间混合起来......

作为最后一点,文档对限制有点不清楚。如果计算Duration返回的两个值之间的差异,则数字溢出本身并不错。由于计数器具有未指定的原点,因此操作的起始值可能接近System.nanoTime(),而结束值接近Long.MAX_VALUE,因为JVM的计数器有溢出。在这种情况下,计算差异将导致另一次溢出,从而产生差异的正确值。但是,如果您将这个差异存储在签名的Long.MIN_VALUE中,它最多可以保持2⁶3纳秒,将差异限制为最长292年,但如果您将其视为 unsigned long ,例如通过Long.compareUnsignedLong.toUnsignedString,您可以处理甚至2⁶⁴纳秒的持续时间,换句话说,如果您的计算机没有中断,您可以通过这种方式测量长达584年的时间...

答案 1 :(得分:1)

我建议您使用getThreadCpuTime中的ThreadMXBean(另请参阅https://stackoverflow.com/a/7467299/185031)。如果你想测量一个方法的执行时间,你大部分时间都不是那么对挂钟感兴趣,而是更多关于CPU执行时间。