当测量低水平的经过时间时,我可以选择使用以下任何一种:
System.currentTimeMillis();
System.nanoTime();
这两种方法都已实施native
。在深入研究任何C代码之前,有没有人知道是否有任何大量的开销要求调用其中一个?我的意思是,如果我真的不关心额外的精度,那么预期哪个CPU耗时更少?
N.B:我使用的是标准的Java 1.6 JDK,但问题可能对任何JRE都有效......
答案 0 :(得分:43)
此页面上标记正确的答案实际上不正确。由于JVM死代码消除(DCE),堆栈替换(OSR),循环展开等,这不是编写基准测试的有效方法。只有像Oracle的JMH微基准测试框架这样的框架才能正确地测量这样的东西。如果您对此类微基准的有效性有任何疑问,请阅读this post。
以下是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();
}
}
以下是结果(在英特尔酷睿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()
在每次调用约118ns时略快于~122ns。然而,同样清楚的是,一旦考虑到平均误差,两者之间几乎没有差别。结果也可能因操作系统而异。但总的说法应该是它们在开销方面基本相同。
更新2015/08/25:虽然这个答案更接近正确,但使用JMH进行衡量,仍然不正确。测量像System.nanoTime()
这样的东西本身就是一种特殊的扭曲基准测试。答案和最终文章是here。
答案 1 :(得分:25)
我不相信你需要担心两者的开销。它是如此微小,它本身几乎无法衡量。以下是两者的快速微观基准:
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()
的两倍。然而,无论如何,29ns将比你测量的任何其他东西短得多。因为它与时钟无关,所以我需要System.nanoTime()
来获得精确度和准确度。
答案 2 :(得分:11)
您应该只使用System.nanoTime()
来衡量某些内容的运行时间。这不仅仅是纳秒级精度的问题,System.currentTimeMillis()
是“挂钟时间”,而System.nanoTime()
用于计时,而不具有另一方的“现实世界时间”怪癖。来自System.nanoTime()
的Javadoc:
此方法只能用于测量经过时间,与系统或挂钟时间的任何其他概念无关。
答案 3 :(得分:6)
System.currentTimeMillis()
通常非常快(afaik 5-6 cpu cycle但我不知道我在哪里读过这个),但它的分辨率因平台而异。
因此,如果您需要高精度,请转到nanoTime()
,如果您担心开销,请转到currentTimeMillis()
。
答案 4 :(得分:6)
如果您有时间,请注意this talk by Cliff Click,他会谈及System.currentTimeMillis
的价格以及其他事项。
答案 5 :(得分:4)
这个问题的接受答案确实是错误的。 @brettw提供的另一个答案是好的,但仍然清楚细节。
有关此主题的完整处理以及这些来电的实际费用,请参阅https://shipilev.net/blog/2014/nanotrusting-nanotime/
回答问题:
是否有人知道是否有任何实质性的开销呼叫一个或另一个?
System#nanoTime
的开销在15到30纳秒之间。 nanoTime
报告的值,其分辨率,每30纳秒只更改一次这意味着,如果您每秒尝试执行数百万次请求,则调用nanoTime
意味着您实际上正在丢失第二次调用nanoTime
的大部分内容。对于此类用例,请考虑测量来自客户端的请求,从而确保您不会陷入coordinated omission,测量队列深度也是一个很好的指标。
如果你没有尽可能多地将工作塞进一秒钟,那么nanoTime
并不重要,但协调的遗漏仍然是一个因素。
最后,为了完整性,currentTimeMillis
无论成本如何都不能使用。这是因为无法保证在两次通话之间前进。特别是在具有NTP的服务器上,currentTimeMillis
不断移动。更不用说计算机测量的大多数东西都不需要整整一毫秒。
答案 6 :(得分:2)
在理论层面,对于使用本机线程并位于现代抢占式操作系统上的VM,currentTimeMillis可以实现为每个时间段只读一次。据推测,nanoTime实现不会牺牲精度。
答案 7 :(得分:0)
currentTimeMillis()
的唯一问题是,当您的VM调整时间时(这通常是自动发生的)currentTimeMillis()
会随之而来,因此会产生未准确的结果,尤其是用于基准测试。