Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 调用Thread.sleep()后,System.nanoTime()测量所用时间的准确性降低_Java_Performance_Nanotime - Fatal编程技术网

Java 调用Thread.sleep()后,System.nanoTime()测量所用时间的准确性降低

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

我在这里遇到了一个非常不寻常的问题。似乎调用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):

但是,在企业服务器上运行它(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以其最大性能状态运行。但是,在
    线程.睡眠
    之后,它可能会陷入其中之一,频率和电压降低。之后,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);
        }
    }