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

Fri*_*jof 62 java performance time

今天我做了一个快速的Benchmark来测试速度性能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));
Run Code Online (Sandbox Code Playgroud)

这是结果:

System.currentTimeMillis(): average of 12.7836022 / function call
System.nanoTime():          average of 34.6395674 / function call
Run Code Online (Sandbox Code Playgroud)

为什么跑步速度的差异如此之大?

基准系统:

Java 1.7.0_25
Windows 8 64-bit
CPU: AMD FX-6100
Run Code Online (Sandbox Code Playgroud)

Roh*_*ain 67

这个Oracle博客:

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并根据工作频率将其转换为时间值).

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

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

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

  • 很好的答案.此网站:http://stas-blogspot.blogspot.nl/2012/02/what-is-behind-systemnanotime.html有人做了一些研究,并在不同的操作系统上显示System.nanoTime背后的源代码. (11认同)

Eel*_*lke 24

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


Mic*_*rdt 5

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

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