作者:CarpenterLee
https://github.com/CarpenterL...
Java8的Stream API能够极大进步Java程序员的生产力,让程序员写出高效率、洁净、简洁的代码。
那么,Stream API的性能到底如何呢,代码整洁的背地是否意味着性能的损耗呢?本文对Stream API的性能一探到底。
为保障测试后果真实可信,咱们将JVM运行在 -server
模式下,测试数据在GB量级,测试机器采纳常见的商用服务器,配置如下:
测试所用代码在这里
https://github.com/CarpenterL...
测试后果汇总
https://github.com/CarpenterL...
测试方法和测试数据
性能测试并不是容易的事,Java性能测试更吃力,因为虚拟机对性能的影响很大,JVM对性能的影响有两方面:
1、GC的影响。GC的行为是Java中很不好管制的一块,为减少确定性,咱们手动指定应用CMS收集器,并应用10GB固定大小的堆内存。个体到JVM参数就是 -XX:+UseConcMarkSweepGC-Xms10G-Xmx10G
2、JIT(Just-In-Time)即时编译技术。即时编译技术会将热点代码在JVM运行的过程中编译成本地代码,测试时咱们会先对程序预热,触发对测试函数的即时编译。相干的JVM参数是 -XX:CompileThreshold=10000
。
Stream并行执行时用到 ForkJoinPool.commonPool()
失去的线程池,为管制并行度咱们应用Linux的 taskset
命令指定JVM可用的核数。
测试数据由程序随机生成。为避免一次测试带来的抖动,测试4次求出均匀工夫作为运行工夫。
试验一 根本类型迭代
测试内容:找出整型数组中的最小值。比照for循环内部迭代和Stream API外部迭代性能。
测试程序 IntTest
https://github.com/CarpenterL...
测试后果如下图:
图中展现的是for循环内部迭代耗时为基准的工夫比值。剖析如下:
1、对于根本类型Stream串行迭代的性能开销显著高于内部迭代开销(两倍);
2、Stream并行迭代的性能比串行迭代和内部迭代都好。
并行迭代性能跟可利用的核数无关,上图中的并行迭代应用了全副12个核,为考查应用核数对性能的影响,咱们专门测试了不同核数下的Stream并行迭代成果:
剖析,对于根本类型:
1、应用Stream并行API在单核状况下性能很差,比Stream串行API的性能还差;
2、随着应用核数的减少,Stream并行成果逐步变好,比应用for循环内部迭代的性能还好。
以上两个测试阐明,对于根本类型的简略迭代,Stream串行迭代性能更差,但多核状况下Stream迭代时性能较好。
试验二 对象迭代
再来看对象的迭代成果。
测试内容:找出字符串列表中最小的元素(天然程序),比照for循环内部迭代和Stream API外部迭代性能。
测试程序StringTest
https://github.com/CarpenterL...
对 Stream 不相熟的,能够关注微信公众号:Java技术栈,在后盾回复:Java。
测试后果如下图:
后果剖析如下:
1、对于对象类型Stream串行迭代的性能开销依然高于内部迭代开销(1.5倍),但差距没有根本类型那么大。
2、Stream并行迭代的性能比串行迭代和内部迭代都好。
再来独自考查Stream并行迭代成果:
剖析,对于对象类型:
1、应用Stream并行API在单核状况下性能比for循环内部迭代差;
2、随着应用核数的减少,Stream并行成果逐步变好,多核带来的成果显著。
以上两个测试阐明,对于对象类型的简略迭代,Stream串行迭代性能更差,但多核状况下Stream迭代时性能较好。
试验三 简单对象归约
从试验一、二的后果来看,Stream串行执行的成果都比内部迭代差(很多),是不是阐明Stream真的不行了?先别下结论,咱们再来考查一下更简单的操作。
测试内容:给定订单列表,统计每个用户的总交易额。比照应用内部迭代手动实现和Stream API之间的性能。
咱们将订单简化为 <userName,price,timeStamp>
形成的元组,并用 Order
对象来示意。测试程序ReductionTest
https://github.com/CarpenterL...
测试后果如下图:
剖析,对于简单的归约操作:
1、Stream API的性能广泛好于内部手动迭代,并行Stream成果更佳;
再来考查并行度对并行成果的影响,测试后果如下:
剖析,对于简单的归约操作:
1、应用Stream并行归约在单核状况下性能比串行归约以及手动归约都要差,简略说就是最差的;
2、随着应用核数的减少,Stream并行成果逐步变好,多核带来的成果显著。
以上两个试验阐明,对于简单的归约操作,Stream串行归约成果好于手动归约,在多核状况下,并行归约成果更佳。咱们有理由置信,对于其余简单的操作,Stream API也能体现出类似的性能体现。
论断
上述三个试验的后果能够总结如下:
1、对于简略操作,比方最简略的遍历,Stream串行API性能显著差于显示迭代,但并行的Stream API可能施展多核个性。
2、对于简单操作,Stream串行API性能能够和手动实现的成果匹敌,在并行执行时Stream API成果远超手动实现。
所以,如果出于性能思考
1、对于简略操作举荐应用内部迭代手动实现
2、对于简单操作,举荐应用Stream API
3、在多核状况下,举荐应用并行Stream API来施展多核优势,
4、单核状况下不倡议应用并行Stream API。
如果出于代码简洁性思考,应用Stream API可能写出更短的代码。即便是从性能方面说,尽可能的应用Stream API也另外一个劣势,那就是只有Java Stream类库做了降级优化,代码不必做任何批改就能享受到降级带来的益处。
近期热文举荐:
1.600+ 道 Java面试题及答案整顿(2021最新版)
2.终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!