일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 재정의
- 테스트 코드
- equals
- java
- 열 속성
- redis
- DI
- DDL
- jwt
- 인덱스
- 생성자 주입
- static
- 필드 주입
- KEVISS
- SQL
- StringBuilder
- 바이너리 카운팅
- stream
- 조합
- MSA
- select_type
- Spring
- cache
- jpa
- Test
- AOP
- VUE
- lambda
- docker
- hashcode
- Today
- Total
백엔드 개발자 블로그
순차 스트림 vs 병렬 스트림 본문
SSAFY Collection 수업을 통해 병렬처리 기능을 가진 Stream API의 존재를 알게되었습니다.
해당 수업에서 강사님이 병렬처리 스트림은 스트림을 쪼개고, 스레드를 할당하고, 최종 결과를 하나로 합치는 과정이 필요하기에 빠르지 않을 수 있다는 말씀을 하셨습니다.
저는 평소에 병렬처리는 무조건 빠를거라고 생각했었기에 어떤 경우에 병렬처리 스트림이 더 좋은지 알아보겠습니다.
다양한 경우의 수
- 요소의 수
- 수가 적은 경우 - 순차 처리
- 요소당 처리시간 긴 경우 - 병렬
- 데이터 전송시간보다 오래 걸리는 작업만 병렬처리하기
- 스트림 소스 종류
- ArrayList : 분할이 쉬워서 병렬
- LinkedList : 분할이 어려워서 순차
- 코어의 수
- 싱글코어인 경우 스레드 수만 증가하고 동시성 작업으로 진행되기 때문에 - 순차
- 병렬로 수행하기 어려운 스트림 모델
- 이전 연산의 결과가 완료되어야 넘어갈 수 있는 경우 분할이 안되기에 - 순차
- 박싱의 최소화
- 박싱과 언박싱은 성능을 크게 하락시키기 때문에 - 기본형 사용
- 순서에 의존하는 연산 - 순차
포크/조인 프레임워크
Recursive Task
스레드 풀 사용 -> RecursiveTask<R>의 서브 클래스 구현, R은 병렬화를 통해 연산된 결과 -> copute() 추상메소드 구현 : 테스크를 서브 테스크로 분할하는 로직 + 더이상 분하이 불가능할 때 서브 테스크의 결과를 조합
주의점
join()은 두 서브 테스크를 시작한 뒤 호출
RecursiveTask내에는 ForkJoinPool의 invoke()를 사용하면 안되고 compute()나 fork()메소드 호출해야함
분리된 테스크 중 한 작업에만 compute() 호출 -> 한 테스크는 스레드를 재사용할 수 있어 오버헤드 감소
compute()를
작업 훔치기
많이 분할할 수록 좋음 -> 스레드 간의 작업 부하를 비슷하게 유지할 수 있게 됨
작업이 끝날 때마다 큐의 헤드에서 다른 테스크를 가져와 작업처리
한 스레드에서 작업이 끝나면 다른 스레드의 꼬리에서 작업을 훔쳐옴
Spliterator
분할할 수 있는 반복자
Collection은 spliterator를 구현해놨음
분할과정
trySplit()을 호출하여 Splitarator 생성 x 2^n -> 결과가 null이면 종료
'ETC > 트러블 슈팅' 카테고리의 다른 글
where 절에 별칭을 재사용하지 못하는 이유 (2) | 2024.09.09 |
---|---|
조합 (0) | 2024.08.14 |
트러블 슈팅 목록 (0) | 2024.04.29 |
DI 방법으로 인한 Error (0) | 2023.12.15 |
MacOS, Windows 유니코드 정규화 방식 차이로 인한 모음, 자음 분리 현상 (0) | 2023.08.23 |