牛逼哄洪的 Java 8 Stream,性能也牛逼么?

简介: 牛逼哄洪的 Java 8 Stream,性能也牛逼么?

Java8的Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。


那么,Stream API的性能到底如何呢,代码整洁的背后是否意味着性能的损耗呢?本文对Stream API的性能一探究竟。


为保证测试结果真实可信,我们将JVM运行在 -server模式下,测试数据在GB量级,测试机器采用常见的商用服务器,配置如下:image.png测试所用代码在这里


https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee


测试结果汇总


https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/Stream_performance.xlsx


测试方法和测试数据

性能测试并不是容易的事,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/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/IntTest.java


测试结果如下图:image.png图中展示的是for循环外部迭代耗时为基准的时间比值。分析如下:


1、对于基本类型Stream串行迭代的性能开销明显高于外部迭代开销(两倍);


2、Stream并行迭代的性能比串行迭代和外部迭代都好。


并行迭代性能跟可利用的核数有关,上图中的并行迭代使用了全部12个核,为考察使用核数对性能的影响,我们专门测试了不同核数下的Stream并行迭代效果:

image.png分析,对于基本类型:


1、使用Stream并行API在单核情况下性能很差,比Stream串行API的性能还差;


2、随着使用核数的增加,Stream并行效果逐渐变好,比使用for循环外部迭代的性能还好。


以上两个测试说明,对于基本类型的简单迭代,Stream串行迭代性能更差,但多核情况下Stream迭代时性能较好。


实验二 对象迭代

再来看对象的迭代效果。


测试内容:找出字符串列表中最小的元素(自然顺序),对比for循环外部迭代和Stream API内部迭代性能。


测试程序StringTest


https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/StringTest.java


对 Stream 不熟悉的,可以关注微信公众号:Java技术栈,在后台回复:Java。


测试结果如下图:image.png结果分析如下:

1、对于对象类型Stream串行迭代的性能开销仍然高于外部迭代开销(1.5倍),但差距没有基本类型那么大。

2、Stream并行迭代的性能比串行迭代和外部迭代都好。

再来单独考察Stream并行迭代效果:image.png分析,对于对象类型:


1、使用Stream并行API在单核情况下性能比for循环外部迭代差;


2、随着使用核数的增加,Stream并行效果逐渐变好,多核带来的效果明显。


以上两个测试说明,对于对象类型的简单迭代,Stream串行迭代性能更差,但多核情况下Stream迭代时性能较好。


实验三 复杂对象归约

从实验一、二的结果来看,Stream串行执行的效果都比外部迭代差(很多),是不是说明Stream真的不行了?先别下结论,我们再来考察一下更复杂的操作。


测试内容:给定订单列表,统计每个用户的总交易额。对比使用外部迭代手动实现和Stream API之间的性能。


我们将订单简化为 <userName,price,timeStamp>构成的元组,并用 Order对象来表示。测试程序ReductionTest


https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/perf/StreamBenchmark/src/lee/ReductionTest.java


测试结果如下图:

image.pngimage.png分析,对于复杂的归约操作:


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开发手册(嵩山版)》最新发布,速速下载!



相关文章
|
2月前
|
缓存 算法 Java
Java 实现的局域网管控软件的性能调优
局域网管控软件在企业网络管理中至关重要,但随着网络规模扩大和功能需求增加,其性能可能受影响。文章分析了数据处理效率低下、网络通信延迟和资源占用过高等性能瓶颈,并提出了使用缓存、优化算法、NIO库及合理管理线程池等调优措施,最终通过性能测试验证了优化效果,显著提升了软件性能。
42 1
|
1月前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
59 5
|
20天前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
35 6
|
20天前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
11天前
|
Rust 安全 Java
Java Stream 使用指南
本文介绍了Java中Stream流的使用方法,包括如何创建Stream流、中间操作(如map、filter、sorted等)和终结操作(如collect、forEach等)。此外,还讲解了并行流的概念及其可能带来的线程安全问题,并给出了示例代码。
|
21天前
|
安全 Java API
Java中的Lambda表达式与Stream API的高效结合####
探索Java编程中Lambda表达式与Stream API如何携手并进,提升数据处理效率,实现代码简洁性与功能性的双重飞跃。 ####
24 0
|
1月前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
31 4
|
1月前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
38 1
|
1月前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
2月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
45 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
下一篇
DataWorks