问题描述
我想测试这两个方法中的哪个执行得更快,但是根据我首先运行哪个方法,该方法似乎总是运行得较慢。 我怀疑Eclipse正在使用某种缓存机制来加快第二种方法的执行速度。
private static int method1(int n) {
int result = 0;
for (int i = 0; i < n + 1; ++i) {
result += i;
}
return result;
}
private static int method2(int n) {
int result = 0;
int i = 0;
while (i < n + 1) {
result += i++;
}
return result;
}
这是我用来测试时间差异的主要功能。
long start, end;
start = new Date().getTime();
for (int i = 0; i < 100000; ++i) {
method1(i);
}
end = new Date().getTime();
System.out.println(end - start); // 47
start = new Date().getTime();
for (int i = 0; i < 100000; ++i) {
method2(i);
}
end = new Date().getTime();
System.out.println(end - start); // 32
1楼
使用 ,我得到以下结果(对于n的各种值),每个方法调用的得分以纳秒为单位(更小=更好):
Benchmark (n) Mode Samples Score Error Units
c.a.p.SO31495089.method1 1 avgt 10 2.149 0.027 ns/op
c.a.p.SO31495089.method1 100000 avgt 10 34626.763 441.915 ns/op
c.a.p.SO31495089.method1 1000000000 avgt 10 322506247.405 6774340.047 ns/op
c.a.p.SO31495089.method2 1 avgt 10 2.159 0.028 ns/op
c.a.p.SO31495089.method2 100000 avgt 10 34581.273 571.416 ns/op
c.a.p.SO31495089.method2 1000000000 avgt 10 320011679.005 4049907.844 ns/op
第二轮:
Benchmark (n) Mode Samples Score Error Units
c.a.p.SO31495089.method1 1 avgt 10 2.164 0.029 ns/op
c.a.p.SO31495089.method1 100000 avgt 10 34706.194 365.189 ns/op
c.a.p.SO31495089.method1 1000000000 avgt 10 320269697.300 1696038.683 ns/op
c.a.p.SO31495089.method2 1 avgt 10 2.160 0.040 ns/op
c.a.p.SO31495089.method2 100000 avgt 10 34627.163 325.981 ns/op
c.a.p.SO31495089.method2 1000000000 avgt 10 320698252.840 2332275.430 ns/op
底线:这两种方法的执行情况均与预期的相似(执行时间之差小于测量误差)。
2楼
使用new Date().getTime()
指定挂钟时间 。
但这并不是开发人员真正想要的(在大多数情况下,直到进行使用企业级基准测试的基准测试为止 ),因为挂钟时间受许多后台进程影响,因此,Java提供了更复杂的API来进行测量时间。
为了排除其他系统活动的影响,您需要测量应用程序“用户时间”。
- “ 用户时间 ”是运行应用程序自己的代码所花费的时间。
- “ CPU时间 ”是用户时间加上系统时间。 这是为应用程序使用CPU所花费的总时间。
下面的示例演示使用ManagementFactory.getThreadMXBean()
API的CPU和用户时间计算。
Thread thread = new Thread(){
public void run() {
for (int i = 0; i < 100000; ++i) {
int result = 0;
for (int j = 0; j < i + 1; ++j) {
result += j;
}
}
System.out.println("FOR approach: ThreadCpuTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()/1000000000d);
System.out.println("FOR approach: UserTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadUserTime()/1000000000d);
};
};
thread.start();
Thread thread2 = new Thread(){
public void run() {
for (int i = 0; i < 100000; ++i) {
int result = 0;
int j = 0;
while (j < i + 1) {
result += j++;
}
}
System.out.println("WHILE approach: ThreadCpuTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()/1000000000d);
System.out.println("WHILE approach: UserTime = " + ManagementFactory.getThreadMXBean().getCurrentThreadUserTime()/1000000000d);
};
};
thread2.start();
话虽如此,我真的不确定为什么会出现意外行为,我在Eclipse和IntelliJ IDE中都运行了您的代码,而且我总是得到比WHILE循环快的FOR循环方法。
可能尝试重新启动Eclipse并运行较少的后台进程,或者不运行Eclipse,而是从Java命令行运行测试,以便确保结果 。
从下面的字节码分析中可以看出,WHILE和FOR循环方法生成的字节码相同 ,这意味着将有相同的汇编代码 ,因此CPU将花费相同的时间执行指令 。
但是实际上,当我们在您的IDE中运行或以其他方式运行时,则受后台进程的影响,因此观察到的时间不同。 但是在这种特殊情况下-WHILE v / s FOR,更适合进行字节码分析并得出WHILE和FOR循环方法将花费相同时间的结论。
FOR循环的字节码:
{
public Test2();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 21
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
LineNumberTable:
line 3: 0
line 4: 8
line 3: 15
line 6: 21
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 250 /* chop */
offset_delta = 18
}
WHILE循环的字节码:
{
public Test();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 21
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
LineNumberTable:
line 3: 0
line 4: 2
line 5: 8
line 6: 15
line 8: 21
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 18 /* same */
}
进一步阅读:
3楼
While和For Loop具有相似的性能。
也许这篇类似的文章对您帮助