티스토리 뷰
728x90
반응형
스트림 병렬화는 주의해서 적용하라
- 주류 언어 중 자바는 동시성 프로그래밍 측면에서 항상 앞서왔습니다. 처음 릴리즈된 1996년부터 스레드, 동기화, wait/notify를 지원했습니다.
- 자바로 동시성 프로그램을 작성하기는 쉬워지지만 올바르고 빠르게 작성하는 일은 여전히 어려운 작업입니다. 동시성 프로그래밍을 할때는 안전성과 응답 가능 상태를 유지하기 위해 노력해야하며, 병렬 스트림 파이프라인 프로그래밍에서도 다를바 없습니다.
🧨 Stream API의 병렬화에 문제가 있는 경우
- 아래 예제는 메르센 소수를 20개 생성하는 코드인데 여기서 parallel() 메서드를 호출해서 여러개의 스레드를 활용해 동시성 프로그래밍으로 효율을 높힐 수 있다고 추측할 수 있지만 실제로 1시간이 넘어도 출력하지 못하는 응답 불가 상태에 빠지게 됩니다.
- 그 이유는
- 데이터 소스가 Stream,iterate이거나 중간 연산(limit)을 사용하는 경우 파이프라인 병렬화로 성능 향상을 시킬 수 없습니다.
- 이유는 스트림 라이브러리에서 병렬화 시키는 방법을 찾지 못하기 때문인데 primes() 메서드에서 반환하는 스트림 파이프라인은 무한 스트림이고, limit로 제한을 두니 적절하게 여러 스레드에게 값을 분배할 수 없고, 지연 평가가 되기 때문에 각각의 값들의 참조 지역성도 떨어지게 됩니다.
public class Example {
public static void main(String[] args) {
primes().parallel()
.map(p -> BigInteger.TWO.pow(p.intValueExact()).subtract(BigInteger.ONE))
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(System.out::println);
}
public static Stream<BigInteger> primes() {
return Stream.iterate(BigInteger.TWO, BigInteger::nextProbablePrime);
}
}
💡 병렬화의 효과가 가장 좋을 때는?
- 스트림의 소스가 ArrayList, HashMap, HashSet, ConcurrentHashMap의 인스턴스이거나 배열의 int 범위, long 범위일 때 병렬화의 효과가 가장 좋습니다.
- 이 자료구조들은 모두 데이터를 원하는 크기로 절확하고 손쉽게 나눌 수 있어서 일을 다수의 스레드에 분배하기에 좋다는 특징이 있습니다.
- 나누는 작업은 Spliterator가 담당하며, Spliterator 객체는 Stream이나 Iterable의 spliterator 메서드에서 얻을 수 있습니다.
- 또한 이 자료구조들의 또 다른 중요한 공통점은 원소들을 순차적으로 실행할 때의 참조 지역성이 뛰어나다는 것입니다. 참조 지역성이란 이웃한 원소의 참조들이 메모리에 연속해서 저장되어 있다는 의미입니다.
💡 참조 지역성이 낮으면?
- 참조들이 가리키는 실제 객체가 메모리에서 서로 떨어져 있을 수 있는데, 그러면 참조 지역성이 낮아집니다. 참조 지역성이 낮으면 스레드는 데이터가 주 메모리에서 캐시 메모리로 전송되어 오기를 기다리며 대부분의 시간을 멍하니 낭비하게 됩니다. 따라서 참조 지역성은 다량의 데이터를 처리하는 벌크 연산을 병렬화할 때 아주 중요한 요소로 작용됩니다.
- 참조 지역성이 가장 뛰어난 자료구조는 기본 타입의 배열입니다. 기본 타입 배열에서는(참조가 아닌) 데이터 자체가 메모리에 연속해서 저장되어 있기 때문입니다.
💡 스트림 파이프라인의 종단연산과 병렬화의 관계
- 스트림 파이프라인의 종단 연산의 동작 방식 역시 병렬 수행 효율에 영향을 미칩니다. 종단 연산에서 수행하는 작업략이 파이프라인 전체 작업에서 상당 비중을 차지하면서 순차적인 연산이라면 파이프라인 병렬 수행의 효과는 제한될 수 있습니다.
- 종단 연산 중 병렬화에 가장 적합한 것은 축소입니다. 축소는 파이프라인에서 만들어진 모든 원소를 하나로 합치는 작업으로 Stream의 reduce 메서드 중 하나 또는 min, max, count, sum과 같이 완성된 형태로 제공되는 메서드 중 하나를 선택해 수행합니다.
- anyMatch, allMatch, noneMatch처럼 조건에 맞으면 바로 반환되는 메서드도 병렬화에 적합합니다.
- 반변 가변 축소를 수행하는 Stream의 collect 메서드는 병렬화에 적합하지 않습니다. 이유는 컬렉션을 합치는 부담이 크기 때문입니다.
💡 병렬화에 대해 잘 모르면 쓰지 말자
- 스트림을 잘못 병렬화하면 성능이 나빠질 뿐만 아니라 결과 자체가 잘못되거나 예상치 못한 동작이 발생할 수 있습니다.
- 결과가 잘못되거나 오동작하는것을 안전 실패라 하는데, 안전 실패는 병렬화한 파이프라인이 사용하는 mappers, filters 혹은 프로그래머가 제공한 다른 함수 객체가 명시한대로 동작하지 않을 때 발생할 수 있습니다.
💡 Stream 명세는 함수 객체에 대한 규약
- Stream의 reduce 연산에 건네지는 accumulator(누적기)와 combiner(결합기) 함수는 반드시 결합법칙을 만족해야 합니다.
- 간섭을 받지 않아야 합니다.- 파이프라인이 수행되는 동안 데이터 소스가 변경되지 않아야합니다.
- 상태를 갖지 않아야 합니다.(stateless)
- 이러한 요구 사항을 지키지 못하더라도 순차적으로 실행하면 올바른 결과를 얻을 수 있습니다. 하지만 병렬로 수행하면 기대값이 나오지 않을 수도 있고, 실패할 수도 있으니 주의가 필요합니다.
참고 자료)
https://catsbi.oopy.io/5861b4b5-60fa-4a6e-aadf-5caeafe68b1e
728x90
반응형
'스터디 > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 - Item50. 적시에 방어적 복사본을 만들라 (0) | 2022.08.03 |
---|---|
이펙티브 자바 - Item49. 매개변수가 유효한지 검사하라 (0) | 2022.08.02 |
이펙티브 자바 - Item47. 반환 타입으로는 스트림보다 컬렉션이 낫다 (0) | 2022.08.01 |
이펙티브 자바 - Item46. 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2022.07.31 |
이펙티브 자바 - Item45. 스트림은 주의해서 사용하라 (0) | 2022.07.31 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 람다 표현식
- 자바 백엔드 개발자 추천 도서
- spring boot poi excel download
- pipe and filter architecture
- JDK Dynamic Proxy와 CGLIB의 차이
- @ControllerAdvice
- redis sorted set
- space based architecture
- spring boot redisson sorted set
- transactional outbox pattern
- polling publisher spring boot
- 레이어드 아키텍처란
- redis sorted set으로 대기열 구현
- java userThread와 DaemonThread
- service based architecture
- spring boot redis 대기열 구현
- spring boot 엑셀 다운로드
- pipeline architecture
- 서비스 기반 아키텍처
- microkernel architecture
- redis 대기열 구현
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- spring boot redisson 분산락 구현
- java ThreadLocal
- transactional outbox pattern spring boot
- 공간 기반 아키텍처
- spring boot excel download paging
- 트랜잭셔널 아웃박스 패턴 스프링부트
- spring boot redisson destributed lock
- spring boot excel download oom
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함