NMP-Study / EffectiveJava2022

Effective Java Study 2022
5 stars 0 forks source link

아이템 48. 스트림 병렬화는 주의해서 적용하라 #48

Closed okhee closed 1 year ago

KimYunsang-v commented 1 year ago

자바 멀티 스레드 역사

자바로 동시성 프로그램 작성은 쉬워졌지만, 올바르고 빠르게 작성하는 일은 여전히 어려운 작업이다. 동시성 프로그래밍을 할 때는 안전성(safety)응답 가능(liveness) 상태를 유지해야한다.

메르센 소수 예제

import java.math.BigInteger;
import java.util.stream.Stream;

import static java.math.BigInteger.*;

public class MersennePrimes {
    public static void main(String[] args) {
        primes().map(p -> BigInteger.valueOf(2).pow(p.intValueExact()).subtract(ONE))
                .filter(mersenne -> mersenne.isProbablePrime(50))
                .limit(20)
                .forEach(System.out::println);
    }

   // 소수를 무한히 반환하는 스트림
    static Stream<BigInteger> primes() {
        return Stream.iterate(BigInteger.valueOf(2), BigInteger::nextProbablePrime);
    }
}

데이터 소스가 Stream.iterate거나 중간 연산으로 limit를 쓰면 파이프라인 병렬화로는 성능 개선을 기대할 수 없다.

파이프라인 병렬화는 limit을 다룰 때 CPU 코어가 남는다면 원소를 몇 개 더 처리한 후 제대한 개수 이후의 결과를 버려도 된다고 가정한다.

4개의 코어가 있다고 가정하면 20번째 계산이 수행되는 시점에 (2^20) 코어 3개가 놀게된다. 이 때 21, 22, 23번째 계산이 병렬로 수행되는데 이 계산들이 20번째 계산보다 2배, 4배, 8배의 시간이 더 필요하다. => 즉, 계산이 끝나기 전에 놀고 있는 cpu가 계속 생겨나서 끝도 없이 계산이 반복된다.

스트림의 소스가 ArrayList, HashMap, HashSet, ConcurrentHashMap의 인스턴스거나 배열, int 범위, long 범위일 때 병렬화의 효과가 가장 좋다.

스트림 파이프라인의 종단 연산의 동작 방식이 병렬 수행 효율에 영향을 준다.

스트림을 잘못 병렬화하면 성능이 나빠질 뿐만 아니라 결과 제체가 잘못되거나 예상 못한 동작이 발생할 수 있다.

스트림 병렬화는 오직 성능 최적화 수단이다.

실제로 스트림 병렬화로 효과를 보는 경우는 많지 않다고 한다..