Stream
Stream
Collection, Array 등의 데이터 소스를 함수형 프로그래밍의 Stream 형태로 다룰 수 있도록 지원하는 API
Stream 은 대표적으로 Collection 데이터를 처리하거나 I/O 처리에 스트리밍 방식을 사용한다.
데이터의 필터링, 매핑, 정렬, 집계 등과 대량의 데이터를 처리할 때 효과적으로 사용할 수 있다.
- Stream의 스트리밍 방식
- 데이터를 작은 블록 단위로 분할하여 처리하는 방식 - 대용량 데이터 처리에 효율적
- 멀티코어 CPU 에서 데이터를 빠른속도로 병렬처리 하는데 용이
- 네트워크 통신에서도 분할하여 전송하고 동시에 처리하기 때문에 용이
- 데이터를 끊어서 전송할 수 있어서, 데이터 전송이 중단되거나 끊어졌을 경우 용이
- 데이터를 작은 블록 단위로 분할하여 처리하는 방식 - 대용량 데이터 처리에 효율적
- 지연처리
- 데이터소스에서 Stream 을 생성하면, 중간 연산들은 데이터 처리가 시작되기 전까지 수행되지 않는다.
- 불필요한 데이터 처리를 줄이고, 성능향상에 도움이 될 수 있다.
- 병렬처리
- 데이터 처리과정에서 데이터를 분할하여 병렬로 처리할 수 있어 대용량 데이터 처리에 적합
- 데이터가 분할되어 처리되기 때문에, 순서가 보장되지 않는다.
순서
- Stream 생성
- Collection, Array 등의 다양한 데이터 소스를 이용해 Stream 을 생성한다.
- Collection.stream(), Arrays.stream() 등
- Collection, Array 등의 다양한 데이터 소스를 이용해 Stream 을 생성한다.
- 중간 연산
- Stream 의 요소를 변환하거나 필터링하는 등의 작업을 수행
- filter, map, flatMap, distinct, sorted, limit, skip 등
- Stream 의 요소를 변환하거나 필터링하는 등의 작업을 수행
- 최종 연산
- Stream 의 요소를 처리하고 결과를 반환합니다.
- forEach, toArray, reduce, collect, min, max, count 등
- Stream 의 요소를 처리하고 결과를 반환합니다.
trade-off
장점
- 원본데이터가 변경되지 않는 불변성
- 내부적으로 병렬 처리 가 가능하도록 구현되어 있어, 멀티코어 CPU에서 빠른 속도로 데이터 처리 가능
- 중간연산과 최종연산의 분리
- 데이터를 한 번에 다 읽어들이는 것이 아니라, 필요한 데이터만 읽어들이므로 메모리 사용량 최적화
단점
- 상태 가 없는 연산만을 지원
- 데이터를 스트리밍 방식으로 처리하기 때문에, 작은 데이터셋에선 for / while 문보다 비효율적이다.
- 제네릭 타입을 사용하여 데이터를 처리하기 때문에, 타입추론이 어려울 수 있다.
- 내부적으로 복잡한 작업을 처리하기 위해 많은 객체를 생성하므로, 런타임 오버헤드 가 발생할 수 있다.
Parallel Stream
데이터요소를 처리할때 필요한 작업을 병렬적으로 처리할 수 있는 기능
Stream 자체가 thread-safe 하게 구현되었기 때문에 가능하다.
Stream 인터페이스의 병렬처리를 위해서는 parallel() 메서드를 호출하면 된다.
parallel() 메서드는 요소를 병렬처리하고, 병렬로 실행할 스레드풀을 생성한다.
즉, parallel() 메서드를 호출하면 Stream 연산이 멀티스레드에서 수행되게 된다.
고려사항
비용
- 대용량 데이터를 처리할 때만 사용하는 것이 좋다.
- 보통 연산의 복잡도가 높을수록 효율이 올라간다
- 데이터셋이 작을경우 병렬화 비용이 더 커서 오히려 성능이 저하된다.
- CPU 코어 수를 고려해 사용 전후 처리시간을 비교해서 사용여부 결정필요
thread-safe
- 병렬처리 시 스레드 풀내에서 별도의 스레드에서 처리될 수 있다.
- Stream의 각 요소는 불변성을 유지해야 한다.
- Stream의 상태를 공유하지 않아야 한다.
순서
- 병렬처리로 작업의 순서가 보장되지 않기 때문에 순서에 의존하는 연산에서 문제가 발생한다.
- ex) 순서에 의존하는 sorted 연산에서 문제가 발생할 수 있다.
- sequential() 메서드 등의 순차처리를 지정하거나 다른방법을 사용해야 함
ForkJoinPool
- parallelStream은 내부적으로 ForkJoinPool 을 사용해 데이터를 병렬처리 한다.
- 스레드 풀을 관리하고, 각 스레드에 작업을 분배하는 기능을 수행한다.
병목현상
- 병목현상에 주의하자.
trade-off
장점
- 여러 코어를 사용해 빠른 처리속도
- 병렬처리를 위해 스레드를 직접 구현할 필요없이 간단하게 구현가능
단점
- 데이터셋이 작을경우 오히려 병렬화 비용이 더 높아서 오버헤드 발생
- 작업의 순서가 보장되지 않음
- 분산환경에선 작동하지 않음
- 내부적으로 중간데이터를 저장하는데 사용하는 메모리 사용량 증가
댓글남기기