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

时间:2013-09-27 13:41:38

标签: 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));

结果如下:

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

4 个答案:

答案 0 :(得分:65)

来自this Oracle blog

  

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()。在大多数系统上,它将提供微秒级的分辨率。但请注意,此调用在某些平台上也可能需要几微秒才能执行

答案 1 :(得分:24)

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

答案 2 :(得分:4)

可能只在Windows上出现这种情况。有关类似问题,请参阅this answer

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

答案 3 :(得分:1)

你在Windows上测量它,不是你。我在2008年进行了这个练习。在Windows上,nanoTime比currentTimeMillis慢。我记得,在Linux上,nanime比currentTimeMillis更快,并且肯定比在Windows上更快。

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