티스토리 뷰
자바에서 스트림은 연속적인 데이터를 순차적으로 처리한다. 그런데 효율을 위해 멀티코어를 사용하여 병렬스트림으로 처리하는 경우가 있다. 이때 병렬스트림이 내부적으로 어떻게 동작하는지 알아보고자 한다.
병렬스트림은 각각 스레드에서 데이터를 처리할 수 있도록 스트림 요소를 여러 청크로 나눈다. 여기서 청크란 무엇일까? 청크는 스트림 요소를 작은 단위로 분할하는 단위이다.
예를 들어, ["hello", "judy", "smile"] 이 있다고 하자. 그러면 각각 "hello", "judy", "smile"처럼 세 가지로 분할하여 처리하는 것이 효율적일 것이다. 그런데 데이터가 엄청 많다고 하자. 그럴 때는 ["hello", "judy", "smile"]를 하나의 청크로 하여 스레드에 넘겨주는 것이 효율적일 것이다. 이처럼 청크의 길이는 병렬 처리의 성능에 영향을 미칠 수 있으므로 적절한 크기로 설정하는 것이 중요한데, 자바는 자동으로 크기를 결정하여 최적화를 수행한다고 한다.
List<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(String.valueOf(i));
}
list.parallelStream().forEach(item -> {
System.out.printf("%s,%s\n", Thread.currentThread(), item);
});
위 코드를 실행하면 병렬스트림이 어떻게 수행되는지 동작을 볼 수 있다.
결과는 아래와 같다. 살펴보면 100개의 데이터가 있을 때 보통 한 스레드에 item을 연속적으로 약3 ~ 4개씩 처리하는 것을 확인할 수 있다.(아래의 음영은 스레드당 처리한 item이 3~4개가 아닌 것이다)
1000개의 데이터가 있을 때는 아래와 같다. 한 스레드당 item을 연속적으로 약 30~32개 처리하는 것을 확인할 수 있다.
이것이 청크 길이인지에 대해 ChatGPT에게 물어봤는데 애매한 답변을 주었다.
결과적으로 데이터가 많아지면 한 스레드가 연속적으로 처리하는 개수도 그에 비례하여 많아짐을 기억해두면 되겠다. 이것을 청크 길이라고 볼 수 있을지는 잘 모르겠다. 그러나 정확한 것은 청크 길이를 직접 계산하는 것은 어렵다는 것이다.
이때, 병렬 스트림이 내부적으로 몇 개의 스레드를 사용하느냐도 관건이다.
병렬 스트림은 내부적으로 ForkJoinPool을 사용하고, ForkJoinPool은 Runtime.getRuntime().availableProcessors()의 반환값에 상응하는 스레드를 갖는다고 한다. (모던 자바 인 액션 P.245)
나의 경우, 8이 나왔고, 정확하게 수행한 스레드 수는 8이었다.
'공부흔적 > 자바' 카테고리의 다른 글
예외 처리 (0) | 2022.06.22 |
---|---|
파일업로드 테스트(MultipartFile.getByte, MultipartFile.transferTo, MultipartFile.getInputStream) (0) | 2022.06.21 |
try-with-resources와 AutoCloseable 인터페이스 (0) | 2022.04.04 |
형태는 같지만 사실 다른 메서드를 사용하는 메서드 참조 (0) | 2022.03.31 |
Logback 설정에 관하여 (0) | 2022.02.23 |