Java8的Stream API确实很牛,但性能究竟如何?
Stream Performance
已经对 Stream API 的用法鼓吹够多了,用起简洁直观,但性能到底怎么样呢?会不会有很高的性能损失?本节我们对 Stream API 的性能一探究竟。
为保证测试结果真实可信,我们将 JVM 运行在 -server模式下,测试数据在 GB 量级,测试机器采用常见的商用服务器,配置如下:
测试方法和测试数据
性能测试并不是容易的事,Java 性能测试更费劲,因为虚拟机对性能的影响很大,JVM 对性能的影响有两方面:
- GC 的影响。GC 的行为是 Java 中很不好控制的一块,为增加确定性,我们手动指定使用 CMS 收集器,并使用 10GB 固定大小的堆内存。具体到 JVM 参数就是 -XX:+UseConcMarkSweepGC-Xms10G-Xmx10G
- JIT(Just-In-Time) 即时编译技术。即时编译技术会将热点代码在 JVM 运行的过程中编译成本地代码,测试时我们会先对程序预热,触发对测试函数的即时编译。相关的 JVM 参数是 -XX:CompileThreshold=10000。
Stream 并行执行时用到 ForkJoinPool.commonPool()得到的线程池,为控制并行度我们使用 Linux 的 taskset命令指定 JVM 可用的核数。
测试数据由程序随机生成。为防止一次测试带来的抖动,测试 4 次求出平均时间作为运行时间。
实验一 基本类型迭代
测试内容:找出整型数组中的最小值。对比 for 循环外部迭代和 Stream API 内部迭代性能。
测试程序 IntTest,测试结果如下图:
图中展示的是 for 循环外部迭代耗时为基准的时间比值。分析如下:
- 对于基本类型 Stream 串行迭代的性能开销明显高于外部迭代开销(两倍);
- Stream 并行迭代的性能比串行迭代和外部迭代都好。
并行迭代性能跟可利用的核数有关,上图中的并行迭代使用了全部 12 个核,为考察使用核数对性能的影响,我们专门测试了不同核数下的 Stream 并行迭代效果:
分析,对于基本类型:
- 使用 Stream 并行 API 在单核情况下性能很差,比 Stream 串行 API 的性能还差;
- 随着使用核数的增加,Stream 并行效果逐渐变好,比使用 for 循环外部迭代的性能还好。
以上两个测试说明,对于基本类型的简单迭代,Stream 串行迭代性能更差,但多核情况下 Stream 迭代时性能较好。
实验二 对象迭代
再来看对象的迭代效果。
测试内容:找出字符串列表中最小的元素(自然顺序),对比 for 循环外部迭代和 Stream API 内部迭代性能。
测试程序 StringTest,测试结果如下图:
结果分析如下:
- 对于对象类型 Stream 串行迭代的性能开销仍然高于外部迭代开销(1.5 倍),但差距没有基本类型那么大。
- Stream 并行迭代的性能比串行迭代和外部迭代都好。
再来单独考察 Stream 并行迭代效果:
分析,对于对象类型:
- 使用 Stream 并行 API 在单核情况下性能比 for 循环外部迭代差;
- 随着使用核数的增加,Stream 并行效果逐渐变好,多核带来的效果明显。
以上两个测试说明,对于对象类型的简单迭代,Stream 串行迭代性能更差,但多核情况下 Stream 迭代时性能较好。
实验三 复杂对象归约
从实验一、二的结果来看,Stream 串行执行的效果都比外部迭代差(很多),是不是说明 Stream 真的不行了?先别下结论,我们再来考察一下更复杂的操作。
测试内容:给定订单列表,统计每个用户的总交易额。对比使用外部迭代手动实现和 Stream API 之间的性能。
我们将订单简化为 <userName,price,timeStamp>构成的元组,并用 Order对象来表示。测试程序 ReductionTest,测试结果如下图:
分析,对于复杂的归约操作:
- Stream API 的性能普遍好于外部手动迭代,并行 Stream 效果更佳;
再来考察并行度对并行效果的影响,测试结果如下:
分析,对于复杂的归约操作:
- 使用 Stream 并行归约在单核情况下性能比串行归约以及手动归约都要差,简单说就是最差的;
- 随着使用核数的增加,Stream 并行效果逐渐变好,多核带来的效果明显。
以上两个实验说明,对于复杂的归约操作,Stream 串行归约效果好于手动归约,在多核情况下,并行归约效果更佳。我们有理由相信,对于其他复杂的操作,Stream API 也能表现出相似的性能表现。
结论
上述三个实验的结果可以总结如下:
- 对于简单操作,比如最简单的遍历,Stream 串行 API 性能明显差于显示迭代,但并行的 Stream API 能够发挥多核特性。
- 对于复杂操作,Stream 串行 API 性能可以和手动实现的效果匹敌,在并行执行时 Stream API 效果远超手动实现。
所以,如果出于性能考虑,1. 对于简单操作推荐使用外部迭代手动实现,2. 对于复杂操作,推荐使用 Stream API, 3. 在多核情况下,推荐使用并行 Stream API 来发挥多核优势,4. 单核情况下不建议使用并行 Stream API。
如果出于代码简洁性考虑,使用 Stream API 能够写出更短的代码。即使是从性能方面说,尽可能的使用 Stream API 也另外一个优势,那就是只要 Java Stream 类库做了升级优化,代码不用做任何修改就能享受到升级带来的好处。
Java8的Stream API确实很牛,但性能究竟如何?的更多相关文章
- Java8的Stream API使用
前言 这次想介绍一下Java Stream的API使用,最近在做一个新的项目,然后终于可以从老项目的祖传代码坑里跳出来了.项目用公司自己的框架搭建完成后,我就想着把JDK版本也升级一下吧(之前的项目, ...
- 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!
写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*) ,那什么是Stream API呢?Java8中的 ...
- 如何用Java8 Stream API找到心仪的女朋友
传统的的Java 集合操作是有些啰嗦的,当我们需要对结合元素进行过滤,排序等操作的时候,通常需要写好几行代码以及定义临时变量. 而Java8 Stream API 可以极大简化这一操作,代码行数少,且 ...
- Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (1) - 创建 Stream
影子 在学习Spring WebFlux之前,我们先来了解JDK的Stream,虽然他们之间没有直接的关系,有趣的是 Spring Web Flux 基于 Reactive Stream,他们中都带了 ...
- Java8中的Stream API
本篇文章继续介绍Java 8的另一个新特性——Stream API.新增的Stream API与InputStream和OutputStream是完全不同的概念,Stream API是对Java中集合 ...
- 十分钟学会Java8的lambda表达式和Stream API
01:前言一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏 ...
- Java8新特性之三:Stream API
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式.Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找.过滤.筛选等操作 ...
- 十分钟学会Java8:lambda表达式和Stream API
Java8 的新特性:Lambda表达式.强大的 Stream API.全新时间日期 API.ConcurrentHashMap.MetaSpace.总得来说,Java8 的新特性使 Java 的运行 ...
- Java8中的 lambda 和Stream API
前言 由于项目中用到了比较多有关于 Java8 中新的东西,一开始自己只是会写,但是写起来不太顺,然后就在网上找到了一个很好的关于Java8新特性的视频,所以就进行了学习了一下,以下是自己对 la ...
随机推荐
- word打印华文字体出现乱码
乱码原因:打印机自带字体库支持的问题 解决方法:解决方法是修改打印机的设置,不使用打印机的字体,直接使用电脑的字体. 具体操作:控制面板-设备和打印机-选中要设置的打印机-打印首选项-图像品质-设置字 ...
- CRM助力企业迎接数字化浪潮
去年,国家发展改革委官网发布'数字化转型伙伴行动'倡议.倡议政府和社会各界联合起来,共同构建多元化的联合推荐机制,带动全行业数字化转型,构建数字化产业链,培育数字化生态,形成"数字引领.抗击 ...
- 通过Cloudflare开启全站https
Cloudflare 添加域名后,会自动生成通用证书,快速开启全站HTTPS,服务端不用做任何修改,还可以选择多种开启模式 一.注册Cloudflare账号 直接打开网站:https://www.cl ...
- 【山外笔记-工具框架】SVN版本控制系统
[山外笔记-框架工具]SVN版本控制系统 学习资料: 1.本文打印版下载地址:[山外笔记-框架工具笔记]SVN版本控制工具-打印版.pdf 2.SVN和TortoiseSVN在线中文文档:http:/ ...
- tar -zxvf file.tar.gz //解压tar.gz
http://apps.hi.baidu.com/share/detail/37384818 download ADT link http://dl.google.com/android/ADT-0. ...
- IT菜鸟之思科模拟实验(PT)
思科官方的模拟软件:cisco packet tracer 网卡端口类型: Ethernet(以太网) 十兆 FastEthernet 百兆 GigabitEthernet 千兆 交换机的端口默认都是 ...
- SQL注入和XSS攻击
SQL注入 定义:黑客通过在请求的数据中填入特殊字符,影响服务器数据库操作程序正常执行,从而达到攻击的目的. 形式: 拼接SQL: 登录验证:前台输入 username:yan password:12 ...
- 11.7 iostat: I/O信息统计
iostat是I/O statistics(输入/输出统计)的缩写,其主要功能是对系统的磁盘I/O操作进行监视.它的输出主要是显示磁盘读写操作的统计信息,同时也会给出CPU的使用情况.同vmstat命 ...
- visual studio code 快捷键-(转自 浅笑千寻)
Visual Studio Code之常备快捷键 官方快捷键大全:https://code.visualstudio.com/docs/customization/keybindings Visual ...
- MVC、MVP和MVVM的区别
前言 在web1.0时代时,那个时候程序猿还没有前后端之分,更程序员开发的时候,都是要前后端一起写的,前后端的代码都是杂揉在一起,如图下 这种开发模式的话,开发的时候因为不需要和其他人员沟通协作,前后 ...