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

2022-08-31 14:58:55

今天我做了一些快速的基准测试来测试速度性能和: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));

这是结果:

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

为什么跑速的差异这么大?

基准测试系统:

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

答案 1

来自此 Oracle 博客

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

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

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

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

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


答案 2

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


推荐