java stream操作(Java stream性能比较)
环境
Ubuntu 22.04 IntelliJ IDEA 2022.1.3 JDK 17 CPU:8核 ➜ ~ cat /proc/cpuinfo | egrep -ie physical id|cpu cores physical id : 0 cpu cores : 1 physical id : 2 cpu cores : 1 physical id : 4 cpu cores : 1 physical id : 6 cpu cores : 1 physical id : 8 cpu cores : 1 physical id : 10 cpu cores : 1 physical id : 12 cpu cores : 1 physical id : 14 cpu cores : 1目标
文本通过实际测试,从以下几个维度比较Java stream的性能:
stream VS. parallelStream 分步 VS. 总体,分步指的是每次操作都转换为List,下个操作前再转换为stream,而总体指的是全部操作之后再转换为List。显然,总体的性能会好于分步的性能 不同数据量对性能的影响准备
新建maven项目 test0317 。
打开 pom.xml 文件,添加如下内容:
<!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>在 src/test/java/com.example.test0317 目录下创建package package1 ,并创建类 Test0317 :
package com.example.test0317.package1; import org.junit.Test; import java.util.List; import java.util.stream.Stream; public class Test0317 { private List<Double> list1 = null; private long size = 10000000; private long start = 0; private long end = 0; private long time = 0; }测试
测试1(stream,10000000,分步)
@Test public void test1() { System.out.println("\n****** test1: stream, " + size + ", step by step ******"); for (int i = 0; i < 3; i++) { list1 = Stream.generate(Math::random).limit(size).toList(); start = System.currentTimeMillis(); list1 = list1.stream().map(e -> e + 1).toList(); list1 = list1.stream().map(e -> e * 2).toList(); list1 = list1.stream().sorted().toList(); end = System.currentTimeMillis(); time = end - start; System.out.println("time = " + time); } }运行结果如下:
****** test1: stream, 10000000, step by step ****** time = 6062 time = 5931 time = 6917测试2(parallelStream,10000000,分步)
@Test public void test2() { System.out.println("\n****** test2: parallelStream, " + size + ", step by step ******"); for (int i = 0; i < 3; i++) { list1 = Stream.generate(Math::random).limit(10000000).toList(); start = System.currentTimeMillis(); list1 = list1.parallelStream().map(e -> e + 1).toList(); list1 = list1.parallelStream().map(e -> e * 2).toList(); list1 = list1.parallelStream().sorted().toList(); end = System.currentTimeMillis(); time = end - start; System.out.println("time = " + time); } }运行结果如下:
****** test2: parallelStream, 10000000, step by step ****** time = 2038 time = 1822 time = 2000测试3(stream,10000000,总体)
@Test public void test3() { System.out.println("\n****** test3: stream, " + size + ", whole ******"); for (int i = 0; i < 3; i++) { list1 = Stream.generate(Math::random).limit(10000000).toList(); start = System.currentTimeMillis(); list1 = list1.stream().map(e -> e + 1).map(e -> e * 2).sorted().toList(); end = System.currentTimeMillis(); time = end - start; System.out.println("time = " + time); } }运行结果如下:
****** test3: stream, 10000000, whole ****** time = 6118 time = 5774 time = 6310测试4(parallelStream,10000000,总体)
@Test public void test4() { System.out.println("\n****** test4: parallelStream, " + size + ", whole ******"); for (int i = 0; i < 3; i++) { list1 = Stream.generate(Math::random).limit(10000000).toList(); start = System.currentTimeMillis(); list1 = list1.parallelStream().map(e -> e + 1).map(e -> e * 2).sorted().toList(); end = System.currentTimeMillis(); time = end - start; System.out.println("time = " + time); } }运行结果如下:
****** test4: parallelStream, 10000000, whole ****** time = 1771 time = 1873 time = 2011测试5(stream,20000000,分步)
运行结果如下:
****** test1: stream, 20000000, step by step ****** time = 12870 time = 12642 time = 12425测试6(parallelStream,20000000,分步)
运行结果如下:
****** test2: parallelStream, 20000000, step by step ****** time = 4216 time = 4247 time = 4420测试7(stream,20000000,总体)
运行结果如下:
****** test3: stream, 20000000, whole ****** time = 12199 time = 12136 time = 12088测试8(parallelStream,20000000,总体)
运行结果如下:
****** test4: parallelStream, 20000000, whole ****** time = 3526 time = 3796 time = 4105上面的测试中,因为CPU是8核,所以parallelStream最多使用8个线程,而下面的测试是指定使用2线程,方法为在JVM的启动选项(VM options)里设置 -Djava.util.concurrent.ForkJoinPool.common.parallelism=2 ,如下图所示:
测试9(2线程,parallelStream,10000000,分步)
运行结果如下:
****** test2: parallelStream, 10000000, step by step ****** time = 3446 time = 3246 time = 3523测试10(2线程,parallelStream,10000000,总体)
运行结果如下:
****** test4: parallelStream, 10000000, whole ****** time = 3173 time = 3136 time = 3259测试11(2线程,parallelStream,20000000,分步)
运行结果如下:
****** test2: parallelStream, 20000000, step by step ****** time = 7246 time = 7830 time = 7613测试12(2线程,parallelStream,20000000,总体)
运行结果如下:
****** test4: parallelStream, 20000000, whole ****** time = 7292 time = 7438 time = 7109总结
测试结果总结如下:
stream VS. parallelStream stepwise VS. whole 元素个数 平均时间(秒) 速度提升 测试1 stream stepwise 10000000 6.3 baseline 测试2 parallelStream stepwise 10000000 2.0 3.15 测试3 stream whole 10000000 6.1 1.03 测试4 parallelStream whole 10000000 1.9 3.32总结:在8核,10000000个元素的情况下,parallelStream相比stream性能提升很大,而总体相比分步只是略有性能提升。
如果把10000000个元素换为20000000个元素,测试结果如下:
stream VS. parallelStream stepwise VS. whole 元素个数 平均时间(秒) 速度提升 测试5 stream stepwise 20000000 12.6 baseline 测试6 parallelStream stepwise 20000000 4.3 2.93 测试7 stream whole 20000000 12.1 1.04 测试8 parallelStream whole 20000000 3.8 3.32可见,如果元素个数加倍,则对于每个测试结果,运行时间也都几乎加倍,符合线性增长。
总结:在8核,20000000个元素的情况下,parallelStream相比stream性能提升很大,而总体相比分步只是略有性能提升。
另外,若换成2线程,其性能显然在单线程和8线程之间。测试结果如下:
stream VS. parallelStream stepwise VS. whole 元素个数 平均时间(秒) 速度提升 测试9 parallelStream stepwise 10000000 3.3 1.91 测试10 parallelStream whole 10000000 3.1 2.03 测试11 parallelStream stepwise 20000000 7.6 1.66 测试12 parallelStream whole 20000000 7.3 1.73可见,2线程相比单线程,性能提升接近于2倍,但是达不到2倍,这是因为创建和切换线程需要消耗一定的时间和资源,同理,拆分及合并数据也需要消耗一定的时间和资源。
总结:在2线程,10000000或20000000个元素的情况下,parallelStream相比stream的性能提升接近于2倍,而总体相比分步只是略有性能提升。
最后多说一句:在数据量很大(本例中达到千万级别)时,parallelStream相比stream而言,性能有非常大的提升。但是若数据量不大,比如我测试了10000,则parallelStream相比stream,性能不但没有提升,甚至变得更差了,原因前面已经提到了。
不过话说回来,即使parallelStream比起stream性能变差,但因为数据量小,所以消耗的时间总量就少,比如说假设从10毫秒变成15毫秒,虽然多了50%的时间消耗,但是因为绝对值很小,所以问题不大。
从这个角度看来,还是应该尽量用parallelStream来取代stream。
当然,本例只是一个非常简单的模型,在一些复杂的情况下,比如有线程安全的问题,就要考虑应该用stream还是parallelStream。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!