最近一直在使用 Stream API,但是到底流式操作,自动装箱对性能的影响如何,一直没有一个明确的答案,看 Java8 In Action 的时候,看到这个例子,自己也测了下, 基本与书中描述一直。对于合格的 Java 开发者,有个基本的认识是必须的。
package com.example.test;
import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;
public class BenchSum {
public static long measureSumPerf(Function<Long, Long> adder, long n)
{
long fastest = Long.MAX_VALUE;
for (int i = 0; i < 20; i++) {
long start = System.nanoTime();
long sum = adder.apply(n);
long duration = (System.nanoTime() - start) / 1_000_000;
//System.out.println("Result: " + sum);
if (duration < fastest)
{
fastest = duration;
}
}
return fastest;
}
public static long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.reduce(0L, Long::sum);
}
public static long iterativeSum(long n) {
long result = 0;
for (long i = 1L; i <= n; i++)
{
result += i;
}
return result;
}
public static long iterativeSumAutoBox(long n) {
Long result = 0L;
for (Long i = 1L; i <= n; i++)
{
result += i;
}
return result.longValue();
}
public static long rangeClosed(long n)
{
return LongStream.rangeClosed(1L, n)
.reduce(0L, Long::sum);
}
public static long parallelSum(long n)
{
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.parallel()
.reduce(0L, Long::sum);
}
public static long parallelRangeSum(long n)
{
return LongStream.rangeClosed(1L, n)
.parallel()
.reduce(0L, Long::sum);
}
public static void main(String[] args) {
System.out.println("Sequential sum done in : " + measureSumPerf(BenchSum::sequentialSum, 10_000_000) + "m_secs");
System.out.println("Iterative sum done in : " + measureSumPerf(BenchSum::iterativeSum, 10_000_000) + "m_secs");
System.out.println("Iterative autobox sum done in : " + measureSumPerf(BenchSum::iterativeSumAutoBox, 10_000_000) + "m_secs");
System.out.println("LongStream sum done in : " + measureSumPerf(BenchSum::rangeClosed, 10_000_000) + "m_secs");
System.out.println("LongStream parallel sum done in : " + measureSumPerf(BenchSum::parallelRangeSum, 10_000_000) + "m_secs");
System.out.println("parallel sum done in : " + measureSumPerf(BenchSum::parallelSum, 10_000_000) + "m_secs");
}
}
我的运行结果:
Sequential sum done in : 81m_secs
Iterative sum done in : 3m_secs
Iterative autobox sum done in : 56m_secs
LongStream sum done in : 4m_secs
LongStream parallel sum done in : 2m_secs
parallel sum done in : 287m_secs
结论:
- 自动装箱的性能开销在大数据量的程序中是不可忽略的。
- stream API 与 For 循环性能相当,可以放心使用
- 当使用并行流的时候,要做测试,有时候并行流不如串行流