package chap07.ParalleDemo;
import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;
class Accumlator{
public long total = 0;
public void add(long value) {
total += value;
}
}
public class ParallelTest {
public static void main(String[] args) {
//需求:使用并行流测试自然数n的累加效率
//测试顺序流
System.out.println("Sequential sum done in :"+ measureSumPerf(ParallelTest::sequentialSum,1_000_000_0)+"mesecs");
//测试传统迭代
System.out.println("Iterative sum done in :" + measureSumPerf(ParallelTest::iterativeSum, 1_000_000_0) + "mesecs");
//测试并行流
System.out.println("Parallel sum done in :" + measureSumPerf(ParallelTest::parallelStream, 1_000_000_0) + "mesecs");
//测试非Long装箱的并行流
System.out.println("Parallel sum done in :" + measureSumPerf(ParallelTest::rangedSum, 1_000_000_0) + "mesecs");
//错误使用并行流示例
System.out.println("SideEffect parallel sum done in :" + measureSumPerf(ParallelTest::sideEffectParallelSum, 1_000_000_0) + "mesecs");
}
//1.传统外部迭代实现(等价于2的实现)
public static long iterativeSum(long n) {
long res = 0;
for (long i = 1L; i <= n; i++) {
res += i;
}
return res;
}
//2.使用BinaryOperator归约实现
public static long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1).limit(n).reduce(0L, Long::sum);
}
//3.改进使用并行流
public static long parallelStream(long n) {
return Stream.iterate(1L,i->i+1).limit(n).parallel().reduce(0L,Long::sum);
}
//4.针对iterator并行装箱拆箱改进方法:使用LongStream.rangeClosed来直接产生原始类型的long数字,再使用并行流
public static long rangedSum(long n) {
return LongStream.rangeClosed(1,n).parallel().reduce(0L, Long::sum);
}
//5.针对4的错误使用并行流
public static long sideEffectParallelSum(long n) {
Accumlator accumlator = new Accumlator();
LongStream.rangeClosed(1, n).parallel().forEach(accumlator::add);
return accumlator.total;
}
//定义测试函数
public static long measureSumPerf(Function<Long, Long> adder, long n) {
long fastest = Long.MAX_VALUE;
//迭代10次
for (int i = 0; i < 10; 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;
}
}
测试效率结果:
1.Sequential sum done in :70mesecs
2.Iterative sum done in :2mesecs
3.Parallel sum done in :76mesecs
4.Parallel sum done in :0mesecs
5.SideEffect parallel sum done in :0mesecs
Summary:从以上结果1和3可以看出并行流效率反而不如传统迭代方式,并不是说并行流不行。而是iterator这里对Long存在装箱和拆箱的过程,所以效率反而不如传统long的数据的叠加。针对Long的装箱过程,采用4的LongStream.rangeClosed进行改进,该流可以直接对原始long数据进行操作,所以效率明显提高。最后针对5不正确使用并行foreach操作,具体结果如下。它会改变多个县城共享的对象的可变状态,因此使用并行流必须主意避免多线程同时访问叠加器,具体原因:在执行total+=value操作时,并不是原子操作。
Result: 6048226861981
Result: 4705973712057
Result: 6101215404420
Result: 5097981782822
Result: 7411387445417
Result: 2857628543763
Result: 5263044807223
Result: 5587422458217
Result: 2451583038513
Result: 4380427335916
SideEffect parallel sum done in :0mesecs