자바 8부터 parallel 메서드 호출을 통해 파이프라인을 병렬 실행할 수 있는 스트림을 지원.
- 데이터 소스가 Stream.iterate인 경우
iterate 연산은 순서에 의존하는 연산이기 때문에 스트림 원소를 분할하기 어렵다.
- 중간 연산으로 limit을 사용하는 경우.
- 파이프라인 병렬화는 limit을 다룰때 CPU 코어가 남는다면 원소를 몇 개 더 처리한 후,
제한된 개수 이후의 결과를 버려도 아무런 해가 없다고 가정.
- 파이프라인 병렬화는 limit을 다룰때 CPU 코어가 남는다면 원소를 몇 개 더 처리한 후,
- 데이터 소스가 ArrayList, HashMap, HashSet, ConcurrentHashMap의 인스턴스
- 배열, int 범위, long 범위
- 모두 데이터를 원하는 크기로 정확하고 쉽게 나눌 수 있다.
- 다수의 스레드에 일을 분배하기 좋다.
- 참조 지역성이 뛰어나다.
- 이웃한 원소의 참조들이 메모리에 연속해서 저장되어 있음
- 참조 지역성이 낮으면, 스레드는 데이터가 주 메모리에서 캐시 메모리로 전송되어 오기 까지 대기.
- 다량의 데이터를 처리하는 벌크 연산을 병렬화 할 때 매우 중요한 요소로 작용
- 모두 데이터를 원하는 크기로 정확하고 쉽게 나눌 수 있다.
종단 연산의 동작 방식도 병렬 수행 효율에 영향을 미침.
-
적합
- 축소(reduction): 모든 원소를 하나로 합치는 작업
reduce, max, min, count, sum
- 조건에 맞으면 바로 반환하는 메서드
anyMatch, allMatch, nonMatch
- 축소(reduction): 모든 원소를 하나로 합치는 작업
-
부적합
종단 연산에서 수행하는 작업량이 파이프라인 전체 작업에서 상당 비중을 차지하면서 순차적인 연산인 경우- 가변 축소(mutable reduction)
- 컬렉션들을 합치는 부담이 크다.
collect
- 가변 축소(mutable reduction)
스트림을 잘못 병렬화 하면 성능이 나빠지는 것 뿐만 아니라 결과 자체가 잘못 될 수 있다.(안전 실패)
Stream의 reduce 연산에 전달되는 accumulator, combiner 함수는 다음 조건을 만족해야 한다.
- 결합 법칙(associative)를 만족해야 한다.
- 간섭받지 않아야 한다.(non-interfering)
- 데이터 소스의 요소를 변경하지 않아야 함.
- 상태를 가지지 말아야 한다.(stateless)
- 연산 중에 외부 상태를 변경하지 않거나 의존하지 않아야 함.
- 스트림 병렬화는 오직 성능 최적화 수단
- 병렬화에 드는 추가 비용 고려해라
- 스트림 요소 분할/결합
- 스레드 할당
- 성능 테스트 해서 병렬화 할 가치가 있는지 확인해라
- 스트림 안의 원소 수와 원소당 수행되는 코드 줄 수를 곱해 최소 수십만은 되야 성능 향상을 접할 수 있다.