我的目标是编写一个测量方法执行或交易时间以及处理测量的框架,即存储,分析等。事务可能包括调用外部系统,同步或异步等待结果。
围绕该主题已经存在一些问题,例如
所有答案都归结为三种方法来消磨时间
System.currentTimeMillis()
System.nanoTime()
Instant.now()
和Duration
(自Java 8起)我知道,所有这些都有一些影响
此方法的结果取决于平台。在Linux上你获得1ms的分辨率,在Windows中你获得10ms(单核)~15ms(多核)。因此,可以测量大型运行操作或短期运行操作的多次执行。
你得到一个高分辨率的时间测量,具有纳秒精度(但不一定是纳秒精度),并且在292年之后你会得到溢出(我可以忍受)。
从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>
那么最好的方法是什么?有没有我没想过的含义?还有其他选择吗?
答案 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.compareUnsigned
和Long.toUnsignedString
,您可以处理甚至2⁶⁴纳秒的持续时间,换句话说,如果您的计算机没有中断,您可以通过这种方式测量长达584年的时间...
答案 1 :(得分:1)
我建议您使用getThreadCpuTime
中的ThreadMXBean
(另请参阅https://stackoverflow.com/a/7467299/185031)。如果你想测量一个方法的执行时间,你大部分时间都不是那么对挂钟感兴趣,而是更多关于CPU执行时间。