在低级别上测量经过的时间时,我可以选择使用以下任何一种:
System.currentTimeMillis();
System.nanoTime();
这两种方法都是使用native
实现的。在深入了解任何C代码之前,是否有人知道调用其中一个方法是否存在实质性的开销?我的意思是,如果我不关心额外的精度,哪个方法预计会消耗更少的CPU时间?
注意:我正在使用标准的Java 1.6 JDK,但该问题可能适用于任何JRE...
System.currentTimeMillis()
和System.nanoTime()
进行 JMH 基准测试的例子:@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class NanoBench {
@Benchmark
public long currentTimeMillis() {
return System.currentTimeMillis();
}
@Benchmark
public long nanoTime() {
return System.nanoTime();
}
}
以下是在Intel Core i5上的测试结果:
Benchmark Mode Samples Mean Mean err Units
c.z.h.b.NanoBench.currentTimeMillis avgt 16 122.976 1.748 ns/op
c.z.h.b.NanoBench.nanoTime avgt 16 117.948 3.075 ns/op
这表明每次调用 System.nanoTime()
的速度比约为 123 纳秒的另一种方法快了约 118 纳秒。然而,考虑到平均误差后,两者之间的差异非常小。结果也可能因操作系统而异。但总的来说,在开销方面它们基本上是等效的。
更新于2015/08/25:尽管这个答案更接近正确,使用 JMH 进行测量仍然不正确。像 System.nanoTime()
这样的测量本身就是一种特殊的扭曲基准测试。答案和权威文章在这里。
@GenerateMicroBenchmark
注释无法工作。最近它似乎已经更名为 @Benchmark
。 - dajood我认为您不需要担心它们的开销。它们的开销非常小,几乎可以忽略不计。以下是两者的快速微基准测试:
for (int j = 0; j < 5; j++) {
long time = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
long x = System.currentTimeMillis();
}
System.out.println((System.nanoTime() - time) + "ns per million");
time = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
long x = System.nanoTime();
}
System.out.println((System.nanoTime() - time) + "ns per million");
System.out.println();
}
最终结果为:
14297079ns per million
29206842ns per million
看起来System.currentTimeMillis()
比System.nanoTime()
快两倍。但是29纳秒的时间短到你无论如何都会测不出其他东西了。我会选择使用System.nanoTime()
来获得精确度和准确性,因为它没有关联时钟。
clock_gettime()
,差异会是 ~0。 - ninjalj你应该只使用System.nanoTime()
来测量某个操作的运行时间。这不仅是因为纳秒级别的精度,System.currentTimeMillis()
是"墙上钟表时间",而System.nanoTime()
则旨在用于计时,没有另一个方法那样具有"现实世界时间"的怪癖。从System.nanoTime()
的Javadoc中可以看到:
此方法仅可用于测量经过时间,与任何其他系统或墙上钟表时间概念无关。
System.currentTimeMillis()
可能会插入小的时钟调整,从而影响计时。虽然这种情况很少见,但是nanoTime()
旨在进行不受此类问题影响的计时测量。 - ColinDcurrentTimeMillis()
进行定时时将计算机日期更改为一周前,您将得到一个不错的负数!=)但对于nanoTime()
则不是这样。 - ColinDSystem.currentTimeMillis()
通常非常快(据我所知大约需要5-6个CPU周期,但是我已经不记得在哪里读到过了),但其分辨率因不同平台而异。
因此,如果您需要高精度,请使用nanoTime()
,如果担心开销,请使用currentTimeMillis()
。
nanoTime
会导致你在大量时间内失去一个巨大的时间块。对于这种情况,请考虑从客户端测量请求,从而确保您不会陷入协调省略,同时测量队列深度也是一个很好的指标。nanoTime
并不重要,但协调省略仍然是一个因素。currentTimeMillis
。这是因为它不能保证在两次调用之间向前移动。特别是在具有NTP的服务器上,currentTimeMillis
不断在变化。更不用说计算机测量的大多数事物都不需要整个毫秒。在理论层面上,对于使用本地线程的虚拟机,并且运行在现代抢占式操作系统上,currentTimeMillis 可以实现为每个时间片仅读取一次。可以预想,nanoTime 实现不会牺牲精度。
currentTimeMillis()
就不能更精确了。或者因为它不需要很精确,所以可以这样实现。但另一方面,这并不说明哪个更快... - Lukas EdercurrentTimeMillis()
的唯一问题在于当您的虚拟机调整时间时(通常会自动发生),currentTimeMillis()
也会随之变化,从而导致不准确的结果,尤其是在基准测试中。
nanoTime
不映射到实际时间,只应用于测量某事物所花费的时间。 - Powerlord