有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是处理时间度量的最佳方法?

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

围绕这个话题已经有了一些问题,比如

所有的答案归结为三种花时间的方法

  • System.currentTimeMillis()
  • System.nanoTime()
  • Instant.now()Duration(自Java8以来)

我知道,所有这些都有一些含义

系统。currentTimeMillis()

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

系统。纳米时间()

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

即刻的。现在()和持续时间

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

鉴于这些事实,很明显,只有通过System.nanoTime()才能达到最佳精度,但我的问题更多地针对处理一般措施的最佳实践,这不仅包括采取措施,还包括措施处理

  • 即时和持续时间提供了最佳的API支持(计算、比较等),但在标准情况下具有依赖于操作系统的精度,并且内存和创建度量(对象构造、更深的调用堆栈)的开销更大。

  • 系统。nanoTime()和系统。currentTimeMillis()具有不同的精度级别,但只有基本的“api”支持(long上的数学运算),但获取速度更快,存储在内存中的空间更小

那么,最好的方法是什么?有什么我没有想到的暗示吗?还有其他选择吗


共 (2) 个答案

  1. # 1 楼答案

    我建议使用来自ThreadMXBeangetThreadCpuTime(另请参见https://stackoverflow.com/a/7467299/185031)。如果你想测量一个方法的执行时间,大多数时候你对挂钟不太感兴趣,而是对CPU执行时间更感兴趣

  2. # 2 楼答案

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

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

    相比之下,^{}被设计用来测量经过的时间而不是别的。由于它的返回值来源不明,甚至可能是负数,因此该方法返回的两个值之间只有差异才有意义。您甚至可以在文档中找到这一点:

    The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.

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

    最后要指出的是,文档中的限制有点不精确。如果您正在计算System.nanoTime()返回的两个值之间的差,那么数字溢出本身并不坏。由于计数器有一个未指定的原点,操作的起始值可能接近Long.MAX_VALUE,而结束值接近Long.MIN_VALUE,因为JVM的计数器有溢出。在这种情况下,计算差值将导致另一个溢出,从而为差值生成正确的值。但是,如果将该差异存储在有符号的long中,它最多可以容纳2个字符⁶³纳秒,将差异最大限制为292年,但如果您将其视为无符号长,例如通过^{}^{},您甚至可以处理2年⁶⁴ 纳秒的持续时间,换言之,如果你的电脑没有在这段时间内中断,你可以用这种方式测量长达584年的运行时间