【发布时间】:2016-01-15 18:47:51
【问题描述】:
我已经阅读了这篇文章:Performance difference between Java 8 lambdas and anonymous inner classes 并在那里提供了article
上面写着:
Lambda 调用的行为与匿名类调用完全相同
“好的”我说完决定自己写基准,我用过jmh,下面是(我还添加了基准供方法参考)。
public class MyBenchmark {
public static final int TESTS_COUNT = 100_000_000;
@Benchmark
public void testMethod_lambda() {
X x = i -> test(i);
for (long i = 0; i < TESTS_COUNT; i++) {
x.x(i);
}
}
@Benchmark
public void testMethod_methodRefernce() {
X x = this::test;
for (long i = 0; i < TESTS_COUNT; i++) {
x.x(i);
}
}
@Benchmark
public void testMethod_anonymous() {
X x = new X() {
@Override
public void x(Long i) {
test(i);
}
};
for (long i = 0; i < TESTS_COUNT; i++) {
x.x(i);
}
}
interface X {
void x(Long i);
}
public void test(Long i) {
if (i == null) System.out.println("never");
}
}
结果(在 Intel Core i7 4770k 上)是:
Benchmark Mode Samples Score Score error Units
t.j.MyBenchmark.testMethod_anonymous thrpt 200 16,160 0,044 ops/s
t.j.MyBenchmark.testMethod_lambda thrpt 200 4,102 0,029 ops/s
t.j.MyBenchmark.testMethod_methodRefernce thrpt 200 4,149 0,022 ops/s
因此,正如您所见,lambda 和匿名方法调用之间存在 4 倍的差异,其中 lambda 的速度要慢 4 倍。
问题是:我做错了什么或者我对 lambdas 的性能理论有误解?
编辑:
# VM invoker: C:\Program Files\Java\jre1.8.0_31\bin\java.exe
# VM options: <none>
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
【问题讨论】:
-
查看生成的字节码,我注意到匿名类使用
invokespecial构造对象,而lambda 使用invokedynamic。如果您在测试本身之外构造每个对象的一个实例,我很想知道是否存在任何速度差异。 -
为什么要在 JMH 测试中运行循环? JMH 为您执行循环。为什么你使用那个 "never" 东西而不是黑洞?编译器足够聪明,可以优化它。
-
此外,您引用的“Lambda 调用的行为与匿名类调用”完全一样。您方便地省略了脚注。
-
请注意,如果您将 lambda、方法引用和匿名类的创建删除到私有静态字段(并重用它们),您的基准测试表明方法引用和匿名类具有相同的性能,而 lambda性能较差。
-
"我做错了什么?" - 1) 手动编写基准循环是错误的; JMH 为您服务。 2) 结果不被 Blackhole 消耗 => JVM 可能会奇怪地优化代码,而你的测量结果不是你所期望的。
标签: java performance lambda java-8 microbenchmark