java Lambda 与匿名类之间的巨大执行时间差异 [英] Big execution time difference between java Lambda vs Anonymous class

查看:19
本文介绍了java Lambda 与匿名类之间的巨大执行时间差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇针对同一个匿名类创建 java8 lambda 实例的性能.(在 win32 java build 1.8.0-ea-b106 上执行的测量).我创建了一个非常简单的例子,并测量了 java 在创建 lambda 表达式时是否建议对 new 运算符进行一些优化:

I was curious about performance of creation of java8 lambda instances against the same anonymous class. (Measurement performed on win32 java build 1.8.0-ea-b106). I've created very simple example and measured if java propose some optimization of new operator while create lambda expression:

static final int MEASURES = 1000000;
static interface ICallback{
    void payload(int[] a);
}
/**
* force creation of anonymous class many times
*/
static void measureAnonymousClass(){
    final int arr[] = {0};
    for(int i = 0; i < MEASURES; ++i){
        ICallback clb = new ICallback() {
            @Override
            public void payload(int[] a) {
                a[0]++;
            }
        };
        clb.payload(arr);
    }
}
/**
* force creation of lambda many times 
*/
static void measureLambda(){ 
    final int arr[] = {0};
    for(int i = 0; i < MEASURES; ++i){
        ICallback clb = (a2) -> {
            a2[0]++;
        };
        clb.payload(arr);
    }
}

(完整代码可以在那里获取:http://codepad.org/Iw0mkXhD)结果相当可预测 - lambda 获胜 2次.

(Full code can be taken there: http://codepad.org/Iw0mkXhD) The result is rather predictable - lambda wins 2 times.

但是对于闭包来说几乎没有什么变化,这表明 lambda 的时机非常糟糕.匿名类获胜 10 次!所以现在匿名类看起来像:

But really little shift to make closure shows very bad time for lambda. Anonymous class wins 10 times! So now anonymous class looks like:

ICallback clb = new ICallback() {
        @Override
        public void payload() {
            arr[0]++;
        }
    };

而 lambda 的作用如下:

And lambda does as follow:

ICallback clb = () -> {
            arr[0]++;
        };

(完整代码可以在那里获取:http://codepad.org/XYd9Umty)谁能解释一下为什么在处理闭包时存在如此大(坏)的差异?

(Full code can be taken there: http://codepad.org/XYd9Umty ) Can anybody explain me why exists so big (bad) difference in handling of closure?

推荐答案

UPDATE

一些评论想知道我在底部的基准是否有缺陷 - 在引入了大量随机性(以防止 JIT 优化太多东西)之后,我仍然得到类似的结果,所以我倾向于认为它是可以的.

UPDATE

A few comments wondering if my benchmark at the bottom was flawed - after introducing a lot of randomness (to prevent the JIT from optimising too much stuff), I still get similar results so I tend to think it is ok.

与此同时,我遇到了这个演示文稿 由 lambda 实现团队编写.第 16 页显示了一些性能数据:内部类和闭包具有相似的性能/非捕获 lambda 最多快 5 倍.

In the meantime, I have come across this presentation by the lambda implementation team. Page 16 shows some performance figures: inner classes and closures have similar performance / non-capturing lambda are up to 5x times faster.

@StuartMarks 发布了这篇 JVMLS 2013 来自 Sergey Kuksenko 的关于 lambda 性能的演讲.最重要的是,后 JIT 编译、lambdas 和匿名类在当前的 Hostpot JVM 实现上的表现相似.

And @StuartMarks posted this JVMLS 2013 talk from Sergey Kuksenko on lambda performance. The bottom line is that post JIT compilation, lambdas and anonymous classes perform similarly on current Hostpot JVM implementations.

我也运行了你的测试,正如你发布的那样.问题在于,第一种方法的运行时间仅为 20 毫秒,而第二种方法的运行时间仅为 2 毫秒.虽然是 10:1 的比例,但由于测量时间太短,没有任何代表性.

I have also run your test, as you posted it. The problem is that it runs for as little as 20 ms for the first method and 2 ms for the second. Although that is a 10:1 ratio, it is in no way representative because the measurement time is way too small.

然后我修改了你的测试以允许更多的 JIT 预热,我得到了与 jmh 相似的结果(即匿名类和 lambda 之间没有区别).

I have then taken modified your test to allow for more JIT warmup and I get similar results as with jmh (i.e. no difference between anonymous class and lambda).

public class Main {

    static interface ICallback {
        void payload();
    }
    static void measureAnonymousClass() {
        final int arr[] = {0};
        ICallback clb = new ICallback() {
            @Override
            public void payload() {
                arr[0]++;
            }
        };
        clb.payload();
    }
    static void measureLambda() {
        final int arr[] = {0};
        ICallback clb = () -> {
            arr[0]++;
        };
        clb.payload();
    }
    static void runTimed(String message, Runnable act) {
        long start = System.nanoTime();
        for (int i = 0; i < 10_000_000; i++) {
            act.run();
        }
        long end = System.nanoTime();
        System.out.println(message + ":" + (end - start));
    }
    public static void main(String[] args) {
        runTimed("as lambdas", Main::measureLambda);
        runTimed("anonymous class", Main::measureAnonymousClass);
        runTimed("as lambdas", Main::measureLambda);
        runTimed("anonymous class", Main::measureAnonymousClass);
        runTimed("as lambdas", Main::measureLambda);
        runTimed("anonymous class", Main::measureAnonymousClass);
        runTimed("as lambdas", Main::measureLambda);
        runTimed("anonymous class", Main::measureAnonymousClass);
    }
}

两种方法的最后一次运行大约需要 28 秒.

The last run takes about 28 seconds for both methods.

我已经运行了 norelrefers.javaollow"用 jmh 进行相同的测试,底线是这四种方法花费的时间与等效方法一样多:

I have run the same test with jmh and the bottom line is that the four methods take as much time as the equivalent:

void baseline() {
    arr[0]++;
}

换句话说,JIT 内联匿名类和 lambda 并且它们花费的时间完全相同.

In other words, the JIT inlines both the anonymous class and the lambda and they take exactly the same time.

结果摘要:

Benchmark                Mean    Mean error    Units
empty_method             1.104        0.043  nsec/op
baseline                 2.105        0.038  nsec/op
anonymousWithArgs        2.107        0.028  nsec/op
anonymousWithoutArgs     2.120        0.044  nsec/op
lambdaWithArgs           2.116        0.027  nsec/op
lambdaWithoutArgs        2.103        0.017  nsec/op

这篇关于java Lambda 与匿名类之间的巨大执行时间差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆