이펙티브 자바 아이템 48. 스트림 병렬화는 주의해서 적용하라. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.github.sejoung.codetest.stream;import java.math.BigInteger;import java.util.stream.Stream;import static java.math.BigInteger.*;public class ParallelMersennePrimes { public static void main (String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .parallel() .filter(mersenne -> mersenne.isProbablePrime(50 )) .limit(20 ) .forEach(System.out::println); } static Stream<BigInteger> primes () { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } }
스트림 병렬화를 하면 어떻게 될까? 위에 소스는 응답하지 않는다.
이유는 데이터 소스가 Stream.iterate거가 중간연산으로 limt를 쓰면 파이브라인 병렬화로 성능을 개선할수 없다.
대체로 스트림의 소스가 ArrayList, HashMap, HashSet, ConcurrentHashMap의 인스턴스거나 배열, int 범위, long 범위일 때 병렬화의 효과가 가장좋다.
스트림을 잘못 병렬화 하면(응답불가를 포함해) 성능이 나빠질 뿐 아니라 결과 자체가 잘못 되거나 예상치 못한 동작을 한다.
조건이 잘 갖춰지면 parallel 메소드 하나로 거의 프로세서 코어수에 비례하는 성능 향상을 만끽할수 있다.
아래 코드를 보면 잘 나타난다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.github.sejoung.codetest.stream;import org.springframework.util.StopWatch;import java.math.BigInteger;import java.util.stream.LongStream;public class ParallelPrimeCounting { static long pi (long n) { return LongStream.rangeClosed(2 , n) .mapToObj(BigInteger::valueOf) .filter(i -> i.isProbablePrime(50 )) .count(); } public static void main (String[] args) { StopWatch sw = new StopWatch (); sw.start(); System.out.println(pi(10_000_000 )); sw.stop(); System.out.println(sw.getTotalTimeSeconds()); } }
실행 결과
1 2 3 4 664579 37.931 Process finished with exit code 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.github.sejoung.codetest.stream;import org.springframework.util.StopWatch;import java.math.BigInteger;import java.util.stream.LongStream;public class ParallelPrimeCounting { static long pi (long n) { return LongStream.rangeClosed(2 , n) .parallel() .mapToObj(BigInteger::valueOf) .filter(i -> i.isProbablePrime(50 )) .count(); } public static void main (String[] args) { StopWatch sw = new StopWatch (); sw.start(); System.out.println(pi(10_000_000 )); sw.stop(); System.out.println(sw.getTotalTimeSeconds()); } }
실행 결과
1 2 3 4 664579 11.844 Process finished with exit code 0
참조