【发布时间】:2015-11-15 04:18:20
【问题描述】:
我在这里遇到了一个非常不寻常的问题。似乎调用 Thread.sleep(n),其中 n > 0 会导致以下 System.nanoTime() 调用难以预测。
下面的代码演示了这个问题。
在我的电脑上运行它(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 Horizon、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() 来记录开始和结束时间。但是,正如您在上面所注意到的,这并不适用。
有没有办法解决这个问题?
感谢您的任何意见!
【问题讨论】:
-
嗨@TheLima,我明白你的意思。这只是我所面临问题的任意演示。您可以在两者之间放置任意数量的代码,您仍然会注意到相同的结果:Thread.sleep() 确实增加了两次 System.nanoTime() 调用之间的时间
-
您的代码在解释帧中执行。你真的想测量解释器的速度吗?将整个
main正文移动到单独的方法中,并在循环中调用它 100 次。后续调用的结果将大不相同。 -
我已经编辑了 OP 以添加与正在执行的操作相关的重要注释;因为没有它们,可能会有,并且有曾经,混乱............并移动了
startTime和@ 987654328@ 变量退出循环,因为进行这么多不必要的分配应该被视为大罪。 =P -
感谢您的编辑。尽管通常最好将变量保持在适当的范围内。例如,在这种情况下,startTime 和 endTime 不需要超过它们包含的循环。 @TagirValeev,我不太明白你在暗示什么。代码,因为人们误解了(我认为从我的代码中抽象出潜在的问题会有所帮助_向上here
-
@TheLima 正如我所说的那样,作为对您现在已删除的答案的反对理由,将变量声明移出循环字面上没有区别。这些是原始变量,没有对象分配;即使它们是非原始的,当您分配一个新值时,您仍然会分配一个新对象。如果您查看带有在循环内部和外部声明的变量的字节码,它将是相同的。 “大罪”是在没有证据的情况下以优化的名义进行更改。
标签: java performance nanotime