当前位置:  开发笔记 > 编程语言 > 正文

为什么我的java lambda使用虚拟赋值比没有它更快?

如何解决《为什么我的javalambda使用虚拟赋值比没有它更快?》经验,为你挑选了1个好方法。



1> Daniel Lemir..:

(修改后的答案.)

用Java进行基准测试很困难.不过,让我们把JMH抛给它......我将你的基准移植到JMH(参见http://github.com/lemire/microbenchmarks).

这些是相关方法......

    public FooPrime[] basicstream(BenchmarkState s) {
            return (FooPrime[]) s.fooList.stream().map(it -> {
                    return new FooPrime().gamma(it.getAlpha() + it.getBeta());
            }).toArray(FooPrime[]::new);
    }

    public FooPrime[] tweakedbasicstream(BenchmarkState s) {
            return (FooPrime[]) s.fooList.stream().map(it -> {
                    int stuff = it.getAlpha().length();
                    return new FooPrime().gamma(it.getAlpha() + it.getBeta());
            }).toArray(FooPrime[]::new);
    }

这是我跑步的结果......

git clone https://github.com/lemire/microbenchmarks.git
cd microbenchmarks
mvn clean install
java -cp target/microbenchmarks-0.0.1-jar-with-dependencies.jar me.lemire.microbenchmarks.mysteries.MysteriousLambda
Benchmark                                      Mode  Samples      Score    Error  Units
m.l.m.m.MysteriousLambda.basicstream           avgt        5  17013.784 ± 46.536  ns/op
m.l.m.m.MysteriousLambda.tweakedbasicstream    avgt        5  16240.451 ± 67.884  ns/op

奇怪的是,似乎这两个函数并没有以完全相同的平均速度运行,存在相当显着的差异.这是在使用JMH时,这是一个相当不错的基准测试框架.

我一开始以为你的两段代码在逻辑上是等价的,但它们不是.当返回的String对象为null时,显然无用的长度方法访问会强制代码抛出异常.

所以它实际上更接近以下代码...

    @Benchmark
    public FooPrime[] nullbasicstream(BenchmarkState s) {
            return (FooPrime[]) s.fooList.stream().map(it -> {
                    if( it.getAlpha() == null) throw new NullPointerException();
                    return new FooPrime().gamma(it.getAlpha() + it.getBeta());
            }).toArray(FooPrime[]::new);
    }

这甚至比你的调整功能更快......

Benchmark                                      Mode  Samples      Score    Error  Units
m.l.m.m.MysteriousLambda.basicstream           avgt        5  17013.784 ± 46.536  ns/op
m.l.m.m.MysteriousLambda.nullbasicstream       avgt        5  15983.762 ± 92.593  ns/op
m.l.m.m.MysteriousLambda.tweakedbasicstream    avgt        5  16240.451 ± 67.884  ns/op

为什么会这样?

让我们回避Java 8的流编程并用愚蠢的旧方式编写函数,有无空检查:

    @Benchmark
    public FooPrime[] basicsum(BenchmarkState s) {
            int howmany = s.fooList.size();
            FooPrime[] answer = new FooPrime[s.fooList.size()];
            for(int k = 0; k < howmany ; ++k ) {
                    Foo x = s.fooList.get(k);
                    answer[k] = new FooPrime(x.getAlpha() + x.getBeta());
            }
            return answer;
    }

    @Benchmark
    public FooPrime[] basicsumnull(BenchmarkState s) {
            int howmany = s.fooList.size();
            FooPrime[] answer = new FooPrime[s.fooList.size()];
            for(int k = 0; k < howmany ; ++k ) {
                    Foo x = s.fooList.get(k);
                    if(x.getAlpha() == null) throw new NullPointerException();
                    answer[k] = new FooPrime(x.getAlpha() + x.getBeta());
            }
            return answer;
    }

这就是我们如何获得最佳表现......

 m.l.m.m.MysteriousLambda.basicstream                        avgt        5  17019.730 ±  61.982  ns/op
 m.l.m.m.MysteriousLambda.nullbasicstream                    avgt        5  16019.332 ±  62.831  ns/op
 m.l.m.m.MysteriousLambda.basicsum                           avgt        5  15635.474 ± 119.890  ns/op
 m.l.m.m.MysteriousLambda.basicsumnull                       avgt        5  14342.016 ± 109.958  ns/op

但空检查的好处仍然存在.

好.让我们对字符串总和进行基准测试,而不需要任何其他东西(没有自定义类).让我们得到标准和和以及空检查之前的总和:

    @Benchmark
    public void stringsum(BenchmarkState s) {
            for(int k = 0; k < s.N; ++k) s.list3[k] = s.list1[k] + s.list2[k];
    }


    @Benchmark
    public void stringsum_withexcept(BenchmarkState s) {
            for(int k = 0; k < s.N; ++k) {
                    if(s.list1[k] == null) throw new NullPointerException();
                    s.list3[k] = s.list1[k] + s.list2[k];
            }
    }

我们得到null检查减慢了我们...

    m.l.m.m.StringMerge.stringsum               avgt        5  27011.111 ±  4.077  ns/op
    m.l.m.m.StringMerge.stringsum_withexcept    avgt        5  28387.825 ± 82.523  ns/op

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有