티스토리 뷰

 자바에서 스트림은 연속적인 데이터를 순차적으로 처리한다. 그런데 효율을 위해 멀티코어를 사용하여 병렬스트림으로 처리하는 경우가 있다. 이때 병렬스트림이 내부적으로 어떻게 동작하는지 알아보고자 한다.


 병렬스트림은 각각 스레드에서 데이터를 처리할 수 있도록 스트림 요소를 여러 청크로 나눈다. 여기서 청크란 무엇일까? 청크는 스트림 요소를 작은 단위로 분할하는 단위이다.

 예를 들어, ["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이었다.

300x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함