我正在学习算法和算法分析课程。我想知道一个简单的操作+
,-
,/
,*
可以在我的计算机上进行多少操作。所以我写了一个简单的秒表如下:
public class NanosecondsStopWatch implements StopWatch {
private PrintStream stream;
public NanosecondsStopWatch(PrintStream stream) {
this.stream = stream;
}
@Override
public void timeAndPrint(Action action) {
long start = System.nanoTime();
action.doAction();
long end = System.nanoTime();
stream.println(end-start);
}
}
public class TestingOperationsTime {
public static void main(String[] strings) {
StopWatch watch = new NanosecondsStopWatch(System.out);
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2*2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2/2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2-2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2+2;
}
});
}
}
结果如下
2529
454
355
335
但是,如果我改变操作的顺序,请说如下:
public class TestingOperationsTime {
public static void main(String[] strings) {
StopWatch watch = new NanosecondsStopWatch(System.out);
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2-2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2*2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2/2;
}
});
watch.timeAndPrint(new Action() {
@Override
public void doAction() {
int i= 2+2;
}
});
}
}
结果仍然几乎相同:
2494
332
309
326
你怎么解释这种行为?
答案 0 :(得分:5)
有许多因素会影响代码使用的系统时间。例如,如果计算机在您的代码运行时执行context switch,则您获得的时间包括运行其他程序所花费的时间。
为了缓解这种情况,您可以多次运行计时器,比如数千或数百万,并取平均值。
另外,正如@rgettman指出的那样,编译器很可能会优化这些计算,因为它们是在常量值上执行的。这意味着您只计算调用方法和打印输出的开销,而不是执行计算的时间。
答案 1 :(得分:2)
总会有差异,因为您的计算机上还运行其他进程,并且根据操作系统,某些进程将优先于其他进程。您无法确切地预测单个操作需要多少毫秒。它还取决于您的计算机CPU速度。
答案 2 :(得分:2)
编译器在编译时计算常量表达式,你应该使它成为一个接收参数的方法。
其次,对手表的系统调用需要花费几纳秒的时间,所以这个检查永远不会成为现实,你实际得到的是java花多少时间来获取时间。
答案 3 :(得分:1)
这不是一件简单的事情。 简而言之,Java不是衡量事物的正确语言。
Java是一种即时编译语言。这意味着您编写的代码在“虚拟机”中运行,并且可能是完全解释,完全编译或部分编译。 这就是为什么,一般来说,第一次运行总是较慢:它总是被解释。只有在以后,VM才能决定编译它并将已编译的代码与解释过程交换。
此外,从JVM调用系统过程会产生很大的开销,这会以某种方式改变您的测量结果。所以,是的,你可以进行测量,如果你先做一个“预热”循环,让VM知道必须编译给定的方法,然后丢弃第一个结果。但结果并不完全衡量CPU的性能。您应该使用C或汇编程序,即使在这种情况下,您也必须处理上下文切换和操作系统管理,这会改变您的结果。
PS:是的,我没有提到它,因为已经有4个其他答案,但Java编译器并不是那么愚蠢,它将在编译时评估常量操作。i=2*2
已编译为i=4
,因此您不是在测量乘法时间,而是仅测量分配时间。
答案 4 :(得分:0)
2个主要问题(1)你正在调用一个消耗大量资源的函数。 (2)你只执行一次。如果直接运行该语句,或者多次运行它,您将看到执行时间非常短。结果如下time=0ns
public class PerfTest {
public static void main(String[] args) {
long t1 = System.nanoTime();
int i = 2 * 2;
long t2 = System.nanoTime();
System.out.printf("time=%dns", t2 -t1);
}
}