Java Parallel Stream(병렬 스트림)

2023. 5. 28. 22:17개발공부/DevOps

Parallel Stream(병렬 스트림)

회사 코드 리뷰를 하던 중 팀원이 parallel stream을 사용하신 것을 봤습니다. 문서를 보니 여러 스레드를 병렬로 실행해 성능이 높아지는 원리라고 인지했습니다. 그리고 나서 foreach문에 적용해봤는데 성능이 약 5배 가까이 좋아지는 것을 보고 동작 원리를 자세히 알아보았습니다.

본 글의 주된 내용은 참고자료 링크에 표기된 oracle 사 Java Magazine을 참고했습니다.

Stream의 두 종류

  • sequential stream
    : 싱글 스레드를 사용해 element를 순차적으로 처리. 싱글 코어 CPU 사용.
  • parallel stream
    : stream을 여러 substream으로 나눠 처리. 멀티 스레드를 사용해 stream 파이프 라인을 실행하고 산출물을 통합해 최종 결과를 만듦.
    멀티 스레드가 멀티 코어 CPU 환경에서 실행됨.

성능에 영향을 미치는 요소들

  • 스레드는 CPU 코어 수에 중대한 영향을 받지만 다른 요소들도 큰 영향을 미칩니다.
  1. 충분히 큰 데이터 사이즈
  • 데이터 사이즈가 작으면 병렬 스트림을 실행하는 비용이 더 클 수 있기 때문에 충분히 큰 데이터 사이즈일 때 사용하는 것이 좋습니다.
  1. 계산집약적 연산(Computation Intensive Operation)
  • 사실 이 부분은 정확히 이해되지 않습니다.
  • 복잡한 연산일수록 데이터 사이즈가 커야 병렬 스트림이 효과적이다?..
  1. 파이프 라인으로 나누기 쉬운 자료구조
  • ArrayList, HashMap은 substream으로 나누기 쉬워 병렬 스트림에 적합합니다. 반면에 LinkedList나 I/O-based 데이터 소스는 substream으로 나누기 어려워 병렬 스트림에 적합하지 않습니다.

Benchmark is recommended

  • 병렬 스트림을 코드에 적용하기에 앞서 반드시 성능 테스트를 거쳐야 합니다. 가용 자원(CPU)과 연산의 복잡도에 따라 성능이 달라지기 때문입니다.

Fork Join Pool

  • Java 7에 추가된 fork/join 프레임 워크는 병렬 처리 속도를 증가시키는데 사용됩니다. 분할 정복 알고리즘을 사용해 유휴 프로세서 코어가 없도록 효율화합니다.
  • Fort와 Join 단계로 나눠 Fork 단계는 테스크를 작은 테스크들로 쪼개고 작은 테스크들은 각자 다른 스레드들에서 동시에 실행합니다.
  • 모든 작은 테스크들이 실행되면 Join 단계로 넘어갑니다. 작은 테스크들의 결과를 합쳐 최종 결과물을 만듭니다.

싱글 코어 CPU에서 멀티 스레드 작업을 수행할 수 있는 이유

  • StackOverFlow - Java threads and number of cores
  • 답변에 따르면 이전에는 core 수 그대로 스레드를 가져다 썼다고 합니다. 하지만 시간이 지나면서 프로세스는 하나 이상의 스레드를 가진다고 합니다. 싱글코어에서 멀티 스레드로 성능을 향상시키는 원리는 core와 threads를 1:1 매치로 봐선 안된다고 하네요.
  • CPU 코어는 물리 코어, 논리 코어를 따로 가진다고 합니다. 그래서 코어 1개가 꼭 하나의 스레드만 실행시킬 수 있는 건 사실이 아닙니다. 이유는 하드웨어 설계와 파이프 라인 설계가 뛰어나게 되면서 가능해졌다고 합니다.
  • 결론은 CPU 1 코어로 여러 개의 스레드를 실행할 수 있는 사실은 참입니다.

결론

  • parallel stream은 많은 데이터의 자료구조를 복잡한 연산과정이 섞여 있을 때 사용하기에 적합합니다.
  • 여러 스레드를 할당하기 때문에 반드시 성능 테스트를 거쳐야 합니다.
  • 싱글 코어 CPU 환경에서도 다수의 스레드를 실행할 수 있습니다.

참고자료: