<aside> 📖 - 병렬 스트림으로 데이터 병렬 처리하기
</aside>
자바 7 이전에는 컬렉션을 병렬로 처리하기 어려웠다. 데이터를 서브파트로 분할해야하고, 분할된 서브파트를 각각의 스레드로 할당해야하며, 스레드로 랄당한 다음에는 의도치않은 레이스컨디션(경쟁상태)이 발생하지 않도록 적절한 동기화를 추가해야하고 마지막에 부분 결과를 합쳐야한다. → 어우 상당히 번거롭고 귀찮습니다.
이를 자바 7은 더 쉽게 병렬화를 수행하면서 에러를 최소화할 수 있도록 포크/조인 프레임워크 기능을 제공합니다.
이 chapter의 핵심은 내부적으로 어떻게 처리되는지 알아야 하는 것입니다. 집중해주세요 !
병렬 스트림이란 ?
스트림에 parallel 메서드를 호출하면 기존의 함수형 리듀싱 연산이 병렬로 처리된다.
public long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.parallel() //병렬 스트림으로 변환
.reduce(0L, Long::sum);
}
스트림이 여러 청크로 분할되어 각각 리듀싱 연산을 수행한 후 다시 리듀싱 연산으로 합쳐져 결과를 도출한다.
parallel
을 호출하면 스트림 자체에 변화가 생기는 것이 아니라 이후 연산이 병렬로 수행해야 함을 의미하는 불리언 프래그가 설정되는 것이다.
<aside> ❓ 청크를 왜 2개로 나눴을까?? 병렬 리듀싱에서는 주로 요소의 인덱스를 기준으로 청크를 나눕니다. 만약 2개의 스레드로 나눈다고 가정하면 위와 같은 로직인데, 왜 2개로 나누는 것일까? → 두 개의 청크로 나뉘어지면, 각각의 스레드에서는 나뉜 청크를 병렬로 처리하고, 최종 결과를 얻기 위해 각각의 부분 결과를 합칩니다. 청크의 크기와 나누는 방식은 구현에 따라 다를 수 있습니다. ?????? 그래서 왜 2개로 한 것일까.?
</aside>
병렬 스트림의 주의점
리듀싱 과정을 시작하는 시점에 전체 숫자 리스트가 준비되지 않았다면, 스트림을 병렬로 처리할 수 있도록 청크로 분할할 수 없다. → 이 문장은 스트림을 병렬로 처리하는데 있어서 전체 데이터가 준비되어 있지 않으면 병렬 리듀싱을 시작할 수 없다는 것을 나타냅니다. 병렬 리듀싱은 데이터를 여러 스레드로 분할하여 동시에 처리하기 위한 것이기 때문에, 처리할 데이터가 미리 나눠져 있어야 합니다.
스트림을 병렬로 처리할 때, 병렬 리듀싱은 전체 데이터를 작은 청크로 나누어 각각의 스레드에게 할당하고, 각 스레드는 자신에게 할당된 청크를 독립적으로 처리합니다. 이렇게 병렬로 처리되는 과정에서 전체 데이터가 빠르게 처리될 수 있습니다.