Java 调用Thread.sleep()后,System.nanoTime()测量所用时间的准确性降低
我在这里遇到了一个非常不寻常的问题。似乎调用Thread.sleep(n)(其中n>0)会导致以下System.nanoTime()调用不太可预测 下面的代码演示了这个问题 在我的电脑上运行它(rMBP 15“2015,OS X 10.11,jre 1.8.0_40-b26)会输出以下结果:Java 调用Thread.sleep()后,System.nanoTime()测量所用时间的准确性降低,java,performance,nanotime,Java,Performance,Nanotime,我在这里遇到了一个非常不寻常的问题。似乎调用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 H
Control: 48497
Random: 36719
Thread.sleep(0): 48044
Thread.sleep(1): 832271
在运行Windows 8的虚拟机上(VMware Horizon、Windows 8.1是1.8.0_60-b27):
但是,在企业服务器上运行它(VMware、RHEL 6.7、jre 1.6.0_45-b06):
这正是我所期望的结果
显然,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);
}
}
公共类主{
公共静态void main(字符串[]args){
int N=1000;
长时间运行=0;
长起始时间,结束时间=0;
对于(int i=0;i
基本上,我是在while循环中运行搜索,通过调用Thread.sleep(),每次迭代都会中断。我想从运行搜索所花费的总时间中排除睡眠时间,所以我使用System.nanoTime()来记录开始和结束时间。但是,正如您在上文中所注意到的,这并不能很好地工作
有办法补救吗
感谢您的支持!不一致可能不是来自Java,而是来自不同的OSs和VM“原子”或系统时钟本身 根据官方的
.nanoTime()
文档:
除了决议至少同样有效外,没有做出任何保证
与currentTimeMillis()相同
…据我个人所知,这是因为在某些操作系统和虚拟机中,系统本身不支持“原子”时钟,这是提高分辨率所必需的。(我会在再次找到这些信息时发布链接以获取这些信息…这已经是很长时间了。)这是一个复杂的主题,因为JVM使用的计时器高度依赖CPU和操作系统,并且随着JVM版本的变化而变化(例如,通过使用较新的操作系统API)。虚拟机还可能限制它们传递给来宾的CPU能力,这可能会改变与裸机设置相比的选择 在x86上,RDTSC指令提供了所有时钟中的最低延迟和最佳粒度,但在某些配置下,它作为时间源不可用或不够可靠 在linux上,您应该检查内核启动消息(
dmesg
)、与tsc相关的/proc/cpuinfo
标志和所选的/sys/devices/system/clocksource/*/current\u clocksource
。默认情况下,内核将尝试使用tsc,如果不使用,可能有原因
对于某些历史,您可能希望阅读以下内容,但请注意,其中一些文章可能有点过时,TSC的可靠性在过去几年中有了很大提高:
- 通过Java8中引入的日期和时间API在Java9中公开更精确的系统时钟
- (提到
-XX:+假设单调刺激器
手动超控/脚踏枪)
- (提到linux的类似选项
)UseLinuxPosixThreadCPUClocks
- (特别是CPU能力,
)在linux术语中为常量\u tsc tsc\u可靠的不间断\u tsc
线程.睡眠
之后,它可能会陷入其中之一,频率和电压降低。之后,CPU不会立即恢复到其最大性能,这可能需要几纳秒到几微秒线程.睡眠
,线程被取消调度后,它将被调度在计时器事件后再次执行,该事件可能与系统.nanoTime
使用的计时器有关在这两种情况下,你都不能直接解决这个问题-我的意思是
线程。睡眠也会影响实际应用程序中的计时。但是如果测量的有用工作量足够大,那么误差将可以忽略不计。Hi@TheLima,我理解你的意思。这只是我面临的问题的任意演示。你可以在两者之间放置尽可能多的代码,您仍然可以
Control: 1385670
Random: 1202695
Thread.sleep(0): 1393994
Thread.sleep(1): 1413220
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);
}
}