首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >java Lambda与匿名类的执行时间差异很大

java Lambda与匿名类的执行时间差异很大
EN

Stack Overflow用户
提问于 2013-09-25 17:33:56
回答 1查看 10.9K关注 0票数 20

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

代码语言:javascript
复制
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次。

但是对于closure来说,几乎没有什么变化,这对lambda来说是非常糟糕的。匿名类赢了10次!所以现在匿名类看起来像这样:

代码语言:javascript
复制
ICallback clb = new ICallback() {
        @Override
        public void payload() {
            arr[0]++;
        }
    };

lambda的作用如下:

代码语言:javascript
复制
ICallback clb = () -> {
            arr[0]++;
        };

(完整代码可以从那里获取:http://codepad.org/XYd9Umty )有人能解释一下为什么在处理闭包方面存在如此大(糟糕)的差异吗?

EN

回答 1

Stack Overflow用户

发布于 2013-09-25 21:15:15

更新

一些评论怀疑我在底部的基准测试是不是有缺陷-在引入了很多随机性(为了防止JIT优化太多东西)之后,我仍然得到了类似的结果,所以我倾向于认为它是好的。

在此期间,我遇到了lambda实现团队的this presentation。第16页显示了一些性能数据:内部类和闭包具有相似的性能/非捕获lambda快5倍。

@StuartMarks发布了这个JVMLS 2013 talk from Sergey Kuksenko on lambda performance。底线是后JIT编译,lambdas和匿名类在当前Hostpot JVM实现上执行类似。

你的基准

正如您发布的那样,我还运行了您的测试。问题是,对于第一种方法,它只运行20ms,而对于第二种方法,它只运行2ms。虽然这是一个10:1的比率,但它并不具有代表性,因为测量时间太短了。

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

代码语言:javascript
复制
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秒。

JMH微基准

我已经运行了the same test with jmh,底线是这四种方法所需的时间与同等方法一样多:

代码语言:javascript
复制
void baseline() {
    arr[0]++;
}

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

结果摘要:

代码语言:javascript
复制
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
票数 30
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19001241

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档