我的目标是为测量方法执行或事务时间和处理测量(即存储、分析等)编写一个框架。事务可能包括对外部系统的调用,同步或异步地等待结果。
关于这个话题已经有了一些问题,比如
- "如何计时方法的执行时间"
- "测量Java方法的执行时间"
- "System.CurrentTimeMillis与System.NanoTime"
所有的答案归结为三种花时间的方法
- System.currentTimeMillis()。
- 江户十一〔一〕号
- EDOCX1·2和EDOCX1〉3(自Java 8以来)
我知道,所有这些都有一些含义
System.CurrentTimeMillis()。
此方法的结果取决于平台。在Linux上,分辨率为1毫秒,而在Windows上,分辨率为10毫秒(单核)~15毫秒(多核)。因此,可以测量大型运行操作或短期运行操作的多个执行。
System.NanoTime()。
你得到了一个高分辨率的时间测量,纳秒精度(但不一定是纳秒精度),你得到了292年后的溢出(我可以忍受)。
instant.now()和持续时间
因为Java 8有新的时间API。一个瞬间有一个第二个和一个纳米第二个场,因此它在对象的顶部引用两个长值(对于Duration)。你还可以获得毫秒级的精度,这取决于基础时钟(见"纳秒分辨率的Java 8即时")。.实例化是通过调用Instant.now()来完成的,该Instant.now()映射到正常系统时钟的System.currentTimeMillis()上。
考虑到这些事实,很明显,最佳精度只能通过System.nanoTime()实现,但我的问题更多地是针对处理一般措施的最佳实践,这不仅包括采取措施,还包括处理措施。
那么最好的方法是什么呢?有什么我没想到的暗示吗?有什么选择吗?
- 好的书面问题,但可能太宽泛了…我的2分:没有以前的,用jodatime。
- 根据Jorda.Org:"注意,从Java SE 8开始,用户被要求迁移到JavaTimes(JSR-310)——JDK的核心部分,它取代了这个项目。""是的,Joda是第一个在Java中完成适当时间API的,但据我所知,新的"官方"API是好的,可能是预的。在大多数情况下都是炽热的。
- System.NanoTime可能是您的最佳选择(它至少和其他两个选项一样精确,可能更精确,具体取决于OS/CPU/JVM)。如果需要进行一些计算,可以始终从nano创建持续时间。
- @Jodicastilla Fyi,Joda Time项目现在处于维护模式,团队建议迁移到java.time类。请参见Oracle教程。Joda Time和java.time都由同一个人斯蒂芬·科尔伯恩领导。对于Java 6和7,大部分的JavaTimePosiple功能都在TruteTeN后端项目中找到。
- 请参阅:JMH,一个用于构建、运行和分析Neal/Mix/MiLy/Me宏基准和JEP 230:微基准套件的Java线束,以及如何在Java中编写正确的微基准?.
你过于关注精度的不重要细节。如果要测量/分析某些操作的执行情况,必须确保这些操作的运行时间足够长,以使测量不受一次性工件、线程调度时间、垃圾收集或热点优化方面的细微差异的影响。在大多数情况下,如果差异小于毫秒尺度,就无法从中得出结论。
更重要的方面是工具是否为您的任务而设计。System.currentTimeMillis()和所有其他基于挂钟的API,不管它们是否基于currentTimeMillis(),都是为了给你一个与地球自转及其绕太阳运行的路径同步的时钟,它给你加载闰秒和其他校正措施的负担,而不是说你的计算机的不管怎样,锁可能与挂钟不同步,并会得到纠正,例如通过NTP更新,在最坏的情况下,当您试图测量您的已用时间,甚至向后跳时。
相比之下,System.nanoTime()的设计目的是测量经过的时间(确切地说是您想要做的),而不是其他任何事情。因为它的返回值有一个未指定的原点,甚至可能是负数,所以只有此方法返回的两个值之间的差异才有任何意义。您甚至可以在文档中找到:
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支持。由于时间点在这里是不相关的,甚至是分散注意力的,所以您只能有一个持续时间,您可以将其转换为其他时间单位,或者,如果您想使用新的时间API,您可以使用Duration.ofNanos(long)创建一个Duration对象,允许您添加和减去持续时间值并进行比较,但是您不能做太多的事情。你不能把它们和挂钟或基于日历的持续时间混在一起…
最后一点要注意的是,文档对限制有点不精确。如果您正在计算由System.nanoTime()返回的两个值之间的差异,那么数字溢出本身并不坏。由于计数器的来源不明,您的操作的起始值可能接近Long.MAX_VALUE,而结束值可能接近Long.MIN_VALUE,因为jvm的计数器溢出。在这种情况下,计算差异将导致另一个溢出,从而产生正确的差异值。但是,如果您将该差异存储在已签名的long中,它最多可以容纳2个?3纳秒,最大限制为292年,但如果您将其视为无符号长,例如通过Long.compareUnsigned和Long.toUnsignedString,您甚至可以处理2??纳秒持续时间,换句话说,如果您的计算机没有在这两者之间中断,您可以用这种方式测量长达584年的时间。
我建议使用来自ThreadMXBean的getThreadCpuTime(另见https://stackoverflow.com/a/7467299/185031)。如果你想测量一个方法的执行时间,你大部分时间对挂钟不太感兴趣,而是对CPU执行时间更感兴趣。
- 我想测量偶尔调用外部系统(即调用WebService)的方法,CPU时间也会覆盖等待时间吗?
- 如果你很忙,等一下。如果是异步的,不。