我已阅读此帖:Performance difference between Java 8 lambdas and anonymous inner classes并提供article
它说:
Lambda调用的行为与匿名类调用完全相同
"确定"我说并决定编写我自己的基准测试,我已经使用了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");
}
}
,它在下面(我还添加了方法参考的基准)。
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
结果(在Intel Core i7 4770k上)是:
# 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
因此,正如您所看到的,lambda和匿名方法调用之间有4倍的差异,其中lambda慢4倍。
问题是:我做错了什么或者我对lambdas的表现理论有误解?
修改:
label1
答案 0 :(得分:9)
问题出在您的基准测试中:您是消除死代码的受害者。
JIT编译器很容易理解,有时自动装箱的结果永远不会为空,所以对于匿名类,它只是删除了你的检查,这反过来使循环体几乎为空。用不太明显的东西(对于JIT)替换它,如下所示:
public void test(Long i) {
if (i == Long.MAX_VALUE) System.out.println("never");
}
您将观察到相同的性能(匿名类变慢,而lambda和方法引用在同一级别执行)。
对于lambda /方法引用,由于某种原因,它没有进行相同的优化。但你不应该担心:你不太可能在实际代码中有这样的方法,可以完全优化。
一般来说@apangin是对的:改用Blackhole。
答案 1 :(得分:5)
除了@TagirValeev提出的问题之外,您正在采取的基准方法存在根本缺陷,因为您正在测量复合指标(尽管您尝试不这样做。)
您想要独立衡量的重要成本是链接,捕获和调用。但是你的所有测试都会将一些测试涂抹在一起,从而中毒你的结果。我的建议是只关注调用成本 - 这与整体应用程序吞吐量最相关,也是最容易测量的(因为它受多个级别的缓存影响较小。)
底线:在动态编译环境中测量性能确实非常困难。即使是JMH。
答案 2 :(得分:0)
我的问题是另一个例子,你不应该做基准测试。我根据其他答案中的建议重新创建了我的测试。
希望现在接近正确性,因为它表明在lambda&和anon的方法调用性能之间没有任何显着差异。见下文:
with cte as (
select auf.anr as anr,
count(*) as num
from Auftrag auf, Table(auf.positionen) po
group by auf.anr
)
select anr
from (select *
from cte
order by num desc)
where rownum = 1