试图对lambda性能进行基准测试

时间:2016-01-15 18:47:52

标签: java performance lambda java-8 microbenchmark

我已阅读此帖:Performance difference between Java 8 lambdas and anonymous inner classes并提供article

它说:

  

Lambda调用的行为与匿名类调用完全相同

&#34;确定&#34;我说并决定编写我自己的基准测试,我已经使用了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

结果(在I​​ntel 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

3 个答案:

答案 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