2015-11-15 33 views
2

我在这里遇到了一个不寻常的真正发行后测量时间的流逝减少。似乎调用Thread.sleep(n),其中n> 0会导致以下System.nanoTime()调用的可预测性较差。精度System.nanoTime()来给了Thread.sleep()的调用

下面的代码演示了这个问题。

我的计算机上运行它(RMBP 15" 2015年,OS X 10.11,JRE 1.8.0_40-B26)输出以下结果:

Control: 48497 
Random: 36719 
Thread.sleep(0): 48044 
Thread.sleep(1): 832271 

在运行Windows 8(VMware的地平线时,Windows虚拟机8.1,是1.8.0_60-B27):

Control: 98974 
Random: 61019 
Thread.sleep(0): 115623 
Thread.sleep(1): 282451 

然而,企业服务器上运行它(VMware的,RHEL 6.7,JRE 1.6.0_45-B06):

Control: 1385670 
Random: 1202695 
Thread.sleep(0): 1393994 
Thread.sleep(1): 1413220 

这是令人惊讶的结果我期望。

显然Thread.sleep代码(1)影响下面的代码的计算。我不知道为什么会发生这种情况。有人有线索吗?

谢谢!

public class Main { 
    public static void main(String[] args) { 
     int N = 1000; 
     long timeElapsed = 0; 
     long startTime, endTime = 0; 

     for (int i = 0; i < N; i++) { 
      startTime = System.nanoTime(); 
      //search runs here 
      endTime = System.nanoTime(); 

      timeElapsed += endTime - startTime; 
     } 

     System.out.println("Control: " + timeElapsed); 

     timeElapsed = 0; 

     for (int i = 0; i < N; i++) { 
      startTime = System.nanoTime(); 
      //search runs here 
      endTime = System.nanoTime(); 

      timeElapsed += endTime - startTime; 

      for (int j = 0; j < N; j++) { 
       int k = (int) Math.pow(i, j); 
      } 
     } 

     System.out.println("Random: " + timeElapsed); 

     timeElapsed = 0; 

     for (int i = 0; i < N; i++) { 
      startTime = System.nanoTime(); 
      //search runs here 
      endTime = System.nanoTime(); 

      timeElapsed += endTime - startTime; 

      try { 
       Thread.sleep(0); 
      } catch (InterruptedException e) { 
       break; 
      } 
     } 

     System.out.println("Thread.sleep(0): " + timeElapsed); 

     timeElapsed = 0; 

     for (int i = 0; i < N; i++) { 
      startTime = System.nanoTime(); 
      //search runs here 
      endTime = System.nanoTime(); 

      timeElapsed += endTime - startTime; 

      try { 
       Thread.sleep(2); 
      } catch (InterruptedException e) { 
       break; 
      } 
     } 

     System.out.println("Thread.sleep(1): " + timeElapsed); 
    } 
} 

基本上我在一个while循环内运行搜索,每次迭代都需要通过调用Thread.sleep()来休息一下。我想排除运行搜索所花费的总时间中的睡眠时间,所以我使用System.nanoTime()来记录开始和结束时间。但是,正如您在上面注意到的那样,这样做效果不佳。

有没有办法来解决这个问题?

感谢任何投入!

+0

嗨@TheLima,我明白你的意思。这只是我面临的问题的一个随意演示。您可以根据需要放置尽可能多的代码,并且您仍然会注意到相同的结果:Thread.sleep()确实增加了两次System.nanoTime()调用之间的时间。 –

+0

您的代码在解释帧中执行。你真的想衡量翻译速度吗?将整个'main'主体移到单独的方法中,并在循环中调用它100次。随后的调用结果将会有很大的不同。 –

+0

我编辑了OP,添加了与正在做什么相关的重要注释;因为如果没有它们,那么可能会有,并且*有*混淆.......................并且将'startTime'和'endTime'变量移出循环,因为使许多不必要的分配应被视为资本罪。 = P – XenoRo

回答

0

这些不一致可能不是来自Java,而是来自不同的操作系统和虚拟机或“系统时钟本身”。

根据官方.nanoTime()文档:

无担保除了分辨率至少为好 为的currentTimeMillis的(生产)

source

.. 。我可以从个人知识中知道这是因为在某些操作系统和虚拟机中,系统本身不支持“原子”时钟,这是更高分辨率所必需的。 (我会后尽快我再次找到它源信息的链接...这是一个很长的时间。)

2

这是一个复杂的话题,因为JVM所使用的定时器是非常CPU和平台 - 也依赖于Java运行时版本。虚拟机也可能会限制它们传递给guest虚拟机的CPU功能,这可能会改变相对于裸机设置的选择。

您可能需要阅读下列

2

我建议至少两种可能原因如下:

  1. 节能。执行繁忙循环时,CPU以最高性能状态运行。但是,在Thread.sleep之后,它可能会落入power-saving states之一,并降低频率和电压。在CPU不会立即恢复到最大性能之后,这可能需要几纳秒到几微秒。
  2. 调度。由于Thread.sleep,在线程被取消预定后,将在计时器事件之后再次执行该线程,其中可能是与用于System.nanoTime的计时器相关。

在这两种情况下,你都不能直接解决这个问题 - 我的意思是Thread.sleep也会影响你的真实应用中的时间。但是,如果所测量的有用工作量足够大,那么不准确性就可以忽略不计。

+0

需要注意的是:英特尔的速度步骤可能需要几百毫秒。英特尔正在开发一种新的更快的速度步骤,以在几毫秒内改变频率。 – Jire