일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 백준
- MSA
- Algorithm
- Proxy
- 자료구조
- 알고리즘
- OS
- JPA
- 자바
- 파이썬
- c언어
- Galera Cluster
- design pattern
- 네트워크
- Spring
- Heap
- react
- Data Structure
- C
- JavaScript
- 운영체제
- Kafka
- 디자인 패턴
- Java
- IT
- spring webflux
- MySQL
- 컴퓨터구조
- mongoDB
- redis
Archives
- Today
- Total
시냅스
Java8 Parallel Stream 과 성능, 동시성 문제에 대해 본문
Parallel Stream
- Stream api 의 일종
- 컬렉션, 배열, 파일 등의 데이터 소스를 처리할 수 있다.
- 스트림을 병렬 처리하여 처리 속도를 높이는 효과가 있다.
- 내부적으로 배열을 가지고 있고, 배열을 쪼개어 각 스레드가 처리하게 된다.
- 요소들이 여러 개의 스레드에 분산되어 병렬 처리된다.
- 분할 정복과 비슷하다.
- 이때 stream api 에서는 스레드 풀을 사용하여 스레드의 생성 및 관리를 담당한다.
- 내부적으로 fork/join 프레임 워크를 사용하여 요소들을 분할하고 각각의 스레드에서 병렬 처리한다.
- 각각의 작업은 스레드 풀의 작업 큐에 추가되고 스레드 풀은 작업 큐에서 작업을 가져와 스레드에 할당한다
// Parallel Stream을 사용한 합계 계산
int sumParallel = Arrays.stream(arr).parallel().sum();
Parallel Stream 이 사용하는 thread pool
- 기본 스레드 풀은 ForkJoinPool.commonPool
- 이 스레드 풀은 기본적으로 시스템의 프로세서 수에 따라 스레드 수를 동적을 조정한다.
- Runtime.availableProcessors 만큼
- 직접 조정할 수도 있지만, 병렬성의 입장에서 추천하지 않는다.
- 다만 ForkJoinPool.commonPool 은 다른 작업에서도 사용되므로 parallel stream 에서 사용할 때는 일부 상황에서 성능 이슈가 발생할 수 있다.
- 함께 사용하는 ForkJoinPool.commonPool 의 작업 큐에 현재 parallel 관련 작업이 아니라 다른 작업이 있을 수도 있기 때문에
- CompletableFuture class 와 같은 비동기 작업
- RecursiveAction, RecursiveTask 와 같이 compute 를 사용하는 작업
- 각 스레드끼리는 만약 스레드 B 에 작업이 몰려있고, A 에 작업이 없다면, A 는 B 의 작업을 가져오며 최적의 성능을 낸다
- 다만 링크드 리스트와 같이 사이즈를 정확히 알기 어려운 자료구조는 분할되지 않아 순차처리하므로 효과를 보기 어렵다
- 물론 size() 를 통해 알 수 있지만, size 를 바꾸는 일은 스레드 간 race condition 을 일으켜 hot spot 이 된다.
- 따라서 분할정복을 적용하기 어렵다.
- 위와 마찬가지로 연산 중간에 변수를 공유해야 되는 작업 (sort, distinct) 들은 내부적으로 상태 변수에 대해 공유(synchronized)해야 하므로 순차적으로 적용하는 것이 보다 효과적일 수 있다.
- 고로 분할이 잘 이루어질 수 있는 데이터 구조이거나, 작업이 독립적이면서 CPU사용이 높은 작업에 적합하다.
- 함께 사용하는 ForkJoinPool.commonPool 의 작업 큐에 현재 parallel 관련 작업이 아니라 다른 작업이 있을 수도 있기 때문에
- 다른 작업 때문에 성능 문제가 우려될 경우 ForkJoinPoll 인스턴스를 만들고 해당 인스턴스를 parallel stream 에 명시적으로 제공하여 사용자 정의 스레드 풀을 만들 수 있다.
// 4개의 스레드를 사용하는 사용자 정의 스레드 풀 생성
ForkJoinPool customThreadPool = new ForkJoinPool(4);
IntStream.range(0, 100).parallel().forEach(i -> {
// 사용자 정의 스레드 풀을 사용하여 parallel stream 실행
}, customThreadPool);
'Java, Spring' 카테고리의 다른 글
Java 로 구현하는 In-Memory Cache (2) | 2023.03.26 |
---|---|
Java 참조 유형 과 GC (strong, soft, weak, phantom reference) (0) | 2023.03.26 |
코드로 뜯어보는 System.out.println 대신 logger 를 사용해야 하는 이유 (0) | 2023.03.19 |
Spring 예제로 보는 보안을 위한 HMAC (2) | 2023.03.11 |
Java 코드 예시로 보는 CSRF 설명과 예방 (4) | 2023.03.09 |
Comments