Java 中时间测量开销
当测量较低级别的经过时间时,我可以选择使用其中任何一种:
System.currentTimeMillis();
System.nanoTime();
这两种方法都是本机
实现的。在深入研究任何 C 代码之前,有谁知道调用其中之一是否会产生大量开销?我的意思是,如果我真的不关心额外的精度,那么哪个精度会消耗更少的 CPU 时间?
注意:我使用的是标准 Java 1.6 JDK,但这个问题可能对任何 JRE 都有效......
When measuring elapsed time on a low level, I have the choice of using any of these:
System.currentTimeMillis();
System.nanoTime();
Both methods are implemented native
. Before digging into any C code, does anyone know if there is any substantial overhead calling one or the other? I mean, if I don't really care about the extra precision, which one would be expected to be less CPU time consuming?
N.B: I'm using the standard Java 1.6 JDK, but the question may be valid for any JRE...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
本页上标记为正确的答案实际上不正确。由于 JVM 死代码消除 (DCE)、栈上替换 (OSR)、循环展开等原因,这不是编写基准测试的有效方法。只有像 Oracle 的 JMH 微基准测试框架这样的框架才能正确测量类似的东西。如果您对有效性有任何疑问,请阅读这篇文章此类微观基准。
() 的 JMH 基准测试:
以下是结果(在 Intel Core i5 上):
以下是
System.currentTimeMillis()
与System.nanoTime >System.nanoTime()
速度稍快,每次调用约为 118 纳秒,而每次调用约为 123 纳秒。然而,同样清楚的是,一旦考虑到平均误差,两者之间的差异就很小了。结果也可能因操作系统而异。但总的结论应该是,它们在开销方面本质上是相当的。2015/08/25 更新:虽然这个答案更接近正确的答案,但使用 JMH 进行测量,它仍然不正确。测量像 System.nanoTime() 这样的东西本身就是一种特殊的扭曲基准测试。答案和权威文章位于此处。
The answer marked correct on this page is actually not correct. That is not a valid way to write a benchmark because of JVM dead code elimination (DCE), on-stack replacement (OSR), loop unrolling, etc. Only a framework like Oracle's JMH micro-benchmarking framework can measure something like that properly. Read this post if you have any doubts about the validity of such micro benchmarks.
Here is a JMH benchmark for
System.currentTimeMillis()
vsSystem.nanoTime()
:And here are the results (on an Intel Core i5):
Which shows that
System.nanoTime()
is slightly faster at ~118ns per invocation compared to ~123ns. However, it is also clear that once the mean error is taken into account, there is very little difference between the two. The results are also likely to vary by operating system. But the general takeaway should be that they are essentially equivalent in terms of overhead.UPDATE 2015/08/25: While this answer is closer to correct that most, using JMH to measure, it is still not correct. Measuring something like
System.nanoTime()
itself is a special kind of twisted benchmarking. The answer and definitive article is here.我认为您不需要担心两者的开销。它是如此之小,以至于它本身几乎无法测量。下面是两者的快速微基准测试:
最后的结果:
System.currentTimeMillis()
的速度确实是System.nanoTime()
的两倍。然而,29 纳秒将比您测量的任何其他时间短得多。为了精度和准确性,我会选择 System.nanoTime(),因为它与时钟无关。I don't believe you need to worry about the overhead of either. It's so minimal it's barely measurable itself. Here's a quick micro-benchmark of both:
And the last result:
It does appear that
System.currentTimeMillis()
is twice as fast asSystem.nanoTime()
. However 29ns is going to be much shorter than anything else you'd be measuring anyhow. I'd go forSystem.nanoTime()
for precision and accuracy since it's not associated with clocks.您应该只使用 System.nanoTime() 来测量运行某些内容所需的时间。这不仅仅是纳秒精度的问题,
System.currentTimeMillis()
是“挂钟时间”,而System.nanoTime()
用于计时而不是有与对方相同的“现实世界时间”怪癖。来自System.nanoTime()
的 Javadoc:You should only ever use
System.nanoTime()
for measuring how long it takes something to run. It's not just a matter of the nanosecond precision,System.currentTimeMillis()
is "wall clock time" whileSystem.nanoTime()
is intended for timing things and doesn't have the "real world time" quirks that the other does. From the Javadoc ofSystem.nanoTime()
:System.currentTimeMillis() 通常非常快(据我所知,需要 5-6 个 cpu 周期,但我不知道我在哪里读过这篇文章),但它的分辨率在不同平台上有所不同。
因此,如果您需要高精度,请选择
nanoTime()
,如果您担心开销,请选择currentTimeMillis()
。System.currentTimeMillis()
is usually really fast (afaik 5-6 cpu cycles but i don't know where i have read this any more), but it's resolution varies on different plattforms.So if you need high precision go for
nanoTime()
, if you are worried about overhead go forcurrentTimeMillis()
.如果您有时间,请观看 Cliff Click 的演讲,他谈到了
System.currentTimeMillis
的价格以及其他事情。If you have time, watch this talk by Cliff Click, he speaks about price of
System.currentTimeMillis
as well as other things.这个问题所接受的答案确实是不正确的。 @brettw 提供的替代答案很好,但仍然缺乏细节。
有关此主题的完整处理以及这些调用的实际成本,请参阅 https:// Shipilev.net/blog/2014/nanotrusting-nanotime/
回答所提出的问题:
nanoTime
报告的值,即其分辨率,每 30 纳秒仅更改一次这意味着,根据您是否尝试每秒执行数百万个请求,调用
nanoTime
意味着您'第二次调用nanoTime
时,我们实际上丢失了很大一部分时间。对于此类用例,请考虑测量来自客户端的请求,从而确保您不会陷入协调遗漏,测量队列深度也是一个很好的指标。如果您不想在一秒钟内塞满尽可能多的工作,那么
nanoTime
并不重要,但协调遗漏仍然是一个因素。最后,为了完整性,无论其成本是多少,都不能使用
currentTimeMillis
。这是因为不能保证在两个调用之间继续进行。特别是在具有 NTP 的服务器上,currentTimeMillis
会不断移动。更不用说计算机测量的大多数东西都不需要一整毫秒。The accepted answer to this question is indeed incorrect. The alternative answer provided by @brettw is good but nonetheless light on details.
For a full treatment of this subject and the real cost of these calls, please see https://shipilev.net/blog/2014/nanotrusting-nanotime/
To answer the asked question:
System#nanoTime
is between 15 to 30 nanoseconds per call.nanoTime
, its resolution, only changes once per 30 nanosecondsThis means depending if you're trying to do million of requests per seconds, calling
nanoTime
means you're effectively losing a huge chunk of the second callingnanoTime
. For such use cases, consider either measuring requests from the client side, thus ensuring you don't fall into coordinated omission, measuring queue depth is also a good indicator.If you're not trying to cram as much work as you can into a single second, than
nanoTime
won't really matter but coordinated omission is still a factor.Finally, for completeness,
currentTimeMillis
cannot be used no matter what its cost is. This is because it's not guaranteed to move forward between two calls. Especially on a server with NTP,currentTimeMillis
is constantly moving around. Not to mention that most things measured by a computer don't take a full millisecond.从理论上讲,对于使用本机线程并位于现代抢占式操作系统上的 VM,currentTimeMillis 可以实现为每个时间片仅读取一次。据推测,nanoTime 实现不会牺牲精度。
At a theoretical level, for a VM that uses native threads, and sits on a modern preemptive operating system, the currentTimeMillis can be implemented to be read only once per timeslice. Presumably, nanoTime implementations would not sacrifice the precision.
currentTimeMillis()
的唯一问题是,当您的虚拟机调整时间时,(这通常会自动发生)currentTimeMillis()
将随之调整,从而产生不准确的结果,特别是对于基准测试。the only problem with
currentTimeMillis()
is that when your VM adjusts time, (this normally happens automatically)currentTimeMillis()
will go with it, thus yielding unacurrate results especially for benchmarking.