-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 아이템 48 : 스트림 병렬화는 주의해서 적용하라 * 아이템 53 : 가변 인수는 신중히 사용하라
- Loading branch information
Showing
2 changed files
with
96 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
## 스트림 병렬화는 주의해서 적용하라 | ||
자바 8부터 parallel 메서드 호출을 통해 파이프라인을 병렬 실행할 수 있는 스트림을 지원. | ||
### 성능 개선이 되지 않는 병렬화 | ||
|
||
- 데이터 소스가 **Stream.iterate**인 경우 | ||
- ~~iterate 연산은 순서에 의존하는 연산이기 때문에 스트림 원소를 분할하기 어렵다.~~ | ||
- 중간 연산으로 **limit**을 사용하는 경우. | ||
- 파이프라인 병렬화는 limit을 다룰때 CPU 코어가 남는다면 원소를 몇 개 더 처리한 후, | ||
제한된 개수 이후의 결과를 버려도 아무런 해가 없다고 가정. | ||
|
||
### 적합한 자료 구조 | ||
- 데이터 소스가 **ArrayList, HashMap, HashSet, ConcurrentHashMap**의 인스턴스 | ||
- **배열, int 범위, long 범위** | ||
- 모두 데이터를 원하는 크기로 정확하고 쉽게 나눌 수 있다. | ||
- 다수의 스레드에 일을 분배하기 좋다. | ||
- **참조 지역성**이 뛰어나다. | ||
- 이웃한 원소의 참조들이 메모리에 연속해서 저장되어 있음 | ||
- 참조 지역성이 낮으면, 스레드는 데이터가 주 메모리에서 캐시 메모리로 전송되어 오기 까지 대기. | ||
- 다량의 데이터를 처리하는 벌크 연산을 병렬화 할 때 매우 중요한 요소로 작용 | ||
|
||
### 종단 연산 | ||
종단 연산의 동작 방식도 병렬 수행 효율에 영향을 미침. | ||
- 적합 | ||
- 축소(reduction): 모든 원소를 하나로 합치는 작업 | ||
- ```reduce, max, min, count, sum``` | ||
- 조건에 맞으면 바로 반환하는 메서드 | ||
- ```anyMatch, allMatch, nonMatch``` | ||
|
||
- 부적합 | ||
종단 연산에서 수행하는 작업량이 파이프라인 전체 작업에서 상당 비중을 차지하면서 순차적인 연산인 경우 | ||
- 가변 축소(mutable reduction) | ||
- 컬렉션들을 합치는 부담이 크다. | ||
- ```collect``` | ||
|
||
### 스트림 명세 | ||
스트림을 잘못 병렬화 하면 성능이 나빠지는 것 뿐만 아니라 결과 자체가 잘못 될 수 있다.(**안전 실패**) | ||
Stream의 reduce 연산에 전달되는 accumulator, combiner 함수는 다음 조건을 만족해야 한다. | ||
- 결합 법칙(associative)를 만족해야 한다. | ||
- 간섭받지 않아야 한다.(non-interfering) | ||
- 데이터 소스의 요소를 변경하지 않아야 함. | ||
- 상태를 가지지 말아야 한다.(stateless) | ||
- 연산 중에 외부 상태를 변경하지 않거나 의존하지 않아야 함. | ||
|
||
### 사용 유의 | ||
- 스트림 병렬화는 오직 성능 최적화 수단 | ||
- 병렬화에 드는 추가 비용 고려해라 | ||
- 스트림 요소 분할/결합 | ||
- 스레드 할당 | ||
- 성능 테스트 해서 병렬화 할 가치가 있는지 확인해라 | ||
- 스트림 안의 원소 수와 원소당 수행되는 코드 줄 수를 곱해 최소 수십만은 되야 성능 향상을 접할 수 있다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
## 가변 인수는 신중히 사용하라 | ||
|
||
가변 인수 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다. | ||
메서드를 호출하면 인수의 개수와 길이가 같은 배열을 생성 후, 메서드에 건네준다. | ||
- 인수가 1개 이상이어야 하는 경우 | ||
- 0개가 받아지도록 설계하는 건 🤮 | ||
```java | ||
public void min(int... args) { | ||
if (args.length == 0) { | ||
throw new IllegalArgumentException(); | ||
} | ||
int min = args[0]; | ||
for (int arg : args) { | ||
if (arg < min) { | ||
min = arg; | ||
} | ||
} | ||
System.out.println(min); | ||
} | ||
``` | ||
- 가변 인수의 갯수로 검증하게끔 하면 런타임에 에러를 확인 할 수 있다. | ||
- 지저분한 코드 | ||
- **필수 매개변수**를 추가로 받도록 하면 된다. | ||
```java | ||
public void min(int firstArg, int... args){ | ||
int min = firstArg; | ||
for(int arg : args){ | ||
if(arg < min){ | ||
min = arg; | ||
} | ||
} | ||
System.out.println(min); | ||
} | ||
``` | ||
- **성능**에 민감한 상황에 가변인수를 사용하는 패턴 | ||
가변 인수 메서드는 호출 될 떄마다 배열을 새로 할당하고 초기화 | ||
이 비용을 감당하기 힘들지만, 가변 인수의 유연성이 필요하다면 다음과 같은 패턴을 적용할 수 있다.<br><br> | ||
ex) 해당 메서드의 호출의 대부분이 인수를 3개 이하로 사용한다면, 다음과 같이 메서드를 다중정의 | ||
```java | ||
public void method(){ ... } | ||
public void method(int a1){ ... } | ||
public void method(int a1, int a2){ ... } | ||
public void method(int a1, int a2, int a3){ ... } | ||
public void method(int a1, int a2, int a3, int... args){ ... } | ||
``` | ||
가변 인수를 사용하는 메서드의 호출 책임을 줄일 수 있다. |