Java 为什么 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19052316/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:43:16  来源:igfitidea点击:

Why is System.nanoTime() way slower (in performance) than System.currentTimeMillis()?

javaperformancetime

提问by Frithjof

Today I did a little quick Benchmark to test speed performance of System.nanoTime()and System.currentTimeMillis():

今天,我做了一些快速的基准来测试速度性能System.nanoTime()System.currentTimeMillis()

long startTime = System.nanoTime();

for(int i = 0; i < 1000000; i++) {
  long test = System.nanoTime();
}

long endTime = System.nanoTime();

System.out.println("Total time: "+(endTime-startTime));

This are the results:

这是结果:

System.currentTimeMillis(): average of 12.7836022 / function call
System.nanoTime():          average of 34.6395674 / function call

Why are the differences in running speed so big?

为什么跑速差异这么大?

Benchmark system:

基准系统:

Java 1.7.0_25
Windows 8 64-bit
CPU: AMD FX-6100

采纳答案by Rohit Jain

From this Oracle blog:

这个 Oracle 博客

System.currentTimeMillis()is implemented using the GetSystemTimeAsFileTime method, which essentially just reads the low resolution time-of-day value that Windows maintains. Reading this global variable is naturally very quick - around 6 cycles according to reported information.

System.nanoTime()is implemented using the QueryPerformanceCounter/ QueryPerformanceFrequency API(if available, else it returns currentTimeMillis*10^6). QueryPerformanceCounter(QPC)is implemented in different ways depending on the hardware it's running on. Typically it will use either the programmable-interval-timer (PIT), or the ACPI power management timer (PMT), or the CPU-level timestamp-counter (TSC). Accessing the PIT/PMT requires execution of slow I/O port instructions and as a result the execution time for QPC is in the order of microseconds. In contrast reading the TSC is on the order of 100 clock cycles (to read the TSC from the chip and convert it to a time value based on the operating frequency).

System.currentTimeMillis()是使用 GetSystemTimeAsFileTime 方法实现的,该方法本质上只是读取 Windows 维护的低分辨率时间值。读取这个全局变量自然非常快——根据报告的信息大约需要 6 个周期。

System.nanoTime()使用 QueryPerformanceCounter/ QueryPerformanceFrequency API(如果可用,否则返回currentTimeMillis*10^6). QueryPerformanceCounter(QPC)以不同方式实现,具体取决于运行的硬件。通常,它将使用可编程间隔计时器(PIT)或 ACPI 电源管理计时器(PMT),或 CPU 级时间戳计数器 (TSC)。访问 PIT/PMT 需要执行慢速 I/O 端口指令,因此 QPC 的执行时间在微秒级。相反,读取 TSC 是在100 个时钟周期的顺序(从芯片读取 TSC 并将其转换为基于工作频率的时间值)。

Perhaps this answer the question. The two methods use different number of clock cycles, thus resulting in slow speed of the later one.

也许这回答了这个问题。这两种方法使用不同数量的时钟周期,从而导致后一种速度慢。

Further in that blog in the conclusion section:

在该博客的结论部分进一步:

If you are interested in measuring/calculating elapsed time, then always use System.nanoTime(). On most systems it will give a resolution on the order of microseconds. Be aware though, this call can also take microseconds to executeon some platforms.

如果您对测量/计算经过时间感兴趣,请始终使用 System.nanoTime()。在大多数系统上,它会给出微秒量级的分辨率。但请注意,在某些平台上执行此调用也可能需要微秒的时间。

回答by Eelke

Most OS's (you didn't mention which one you are using) have an in memory counter/clock which provides millisecond accuracy (or close to that). For nanosecond accuracy most have to read a hardware counter. Communicating with hardware is slower then reading some value already in memory.

大多数操作系统(您没有提到您使用的是哪一个)都有一个内存计数器/时钟,可提供毫秒精度(或接近该精度)。对于纳秒精度,大多数必须读取硬件计数器。与硬件通信比读取内存中已有的值要慢。

回答by Michael Borgwardt

It may only be the case on Windows. See this answerto a similar question.

可能只在 Windows 上是这种情况。请参阅对类似问题的回答。

Basically, System.currentTimeMillis()just reads a global variable maintained by Windows (which is what it has low granularity), whereas System.nanoTime()actually has to do IO operations.

基本上,System.currentTimeMillis()只是读取Windows维护的全局变量(这是它的低粒度),而System.nanoTime()实际上必须进行IO操作。

回答by Walt Corey

You are measuring that on Windows, aren't you. I went through this exercise in 2008. nanoTime IS slower on Windows than currentTimeMillis. As I recall, on Linux, nanotime is faster than currentTimeMillis and is certainly faster than it is on Windows.

你是在 Windows 上测量它,不是吗。我在 2008 年完成了这个练习。nanoTime 在 Windows 上比 currentTimeMillis 慢。我记得,在 Linux 上,nanotime 比 currentTimeMillis 快,而且肯定比在 Windows 上快。

The important thing to note is if you are trying to measure the aggregate of multiple sub-millisecond operations, you must use nanotime as if the operation finished in less than 1/1000th of a second your code, comparing currentTimeMillis will show the operation as instantaneous so 1,000 of these will still be instantaneous. What you might want to do is use nanotime then round to the nearest millisecond, so if an operation took 8000 nanoseconds it will be counted as 1 millisecond, not 0.

需要注意的重要一点是,如果您尝试测量多个亚毫秒级操作的聚合,则必须使用 nanotime,就好像操作在不到 1/1000 秒的代码中完成一样,比较 currentTimeMillis 将显示操作为瞬时的所以其中 1,000 个仍然是即时的。您可能想要做的是使用 nanotime 然后四舍五入到最接近的毫秒,因此如果操作花费了 8000 纳秒,它将被计为 1 毫秒,而不是 0。

回答by dave

What you might want to do is use nanotime then round to the nearest millisecond, so if an operation took 8000 nanoseconds it will be counted as 1 millisecond, not 0.

您可能想要做的是使用 nanotime 然后四舍五入到最接近的毫秒,因此如果操作花费了 8000 纳秒,它将被计为 1 毫秒,而不是 0。

Arithmetic note:

算术说明:

8000 nanoseconds is 8 microseconds is 0.008 milliseconds. Rounding will take that to 0 milliseconds.

8000 纳秒等于 8 微秒等于 0.008 毫秒。舍入会将其设为 0 毫秒。