Java8에 들어간 stream, parallelStream이 좋다는 이야기만 듣고 대충 개념만 이해한 상태에서...
"그냥 좋겠지"란생각으로 쓰려다...
간단하게 테스트 해보고 정리 ^^ 참고로 로컬 PC에서 돌렸으며, 로컬 PC의 물리 cpu 코어 개수는 4개이다.
import java.util.ArrayList;
import java.util.List;
public class StreamTest {
public static void main(String[] args) throws InterruptedException {
List<Integer> intList = new ArrayList<>();
// 테스트할 loop의 개수...
for (int i = 0; i<1000000; i++) {
intList.add(i);
}
// normal for loop
long startTime = System.currentTimeMillis();
for (Integer integer : intList) {
if(integer % 1000 == 0) {
System.out.println(integer);
//Thread.sleep(10);
}
}
long endTime = System.currentTimeMillis();
// stream foreach
long startTime2 = System.currentTimeMillis();
intList.stream().forEach(integer -> {
if(integer % 1000 == 0) {
System.out.println(integer);
try {
//Thread.sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
long endTime2 = System.currentTimeMillis();
// parallelStream foreach
long startTime3 = System.currentTimeMillis();
intList.parallelStream().forEach(integer -> {
if(integer % 1000 == 0) {
System.out.println(integer);
try {
//Thread.sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
long endTime3 = System.currentTimeMillis();
System.out.println("## 1 소요시간(초.0f) : " + ( endTime - startTime )/1000.00f +"초");
System.out.println("## 2 소요시간(초.0f) : " + ( endTime2 - startTime2 )/1000.00f +"초");
System.out.println("## 3 소요시간(초.0f) : " + ( endTime3 - startTime3 )/1000.00f +"초");
}
}
10만건, 100만건 테스트를 그냥 간단하게 2, 3회 정도 실시해 본 결과는 아래와 같다.
10만
## 1 소요시간(초.0f) : 0.005초
## 2 소요시간(초.0f) : 0.058초
## 3 소요시간(초.0f) : 0.013초
## 1 소요시간(초.0f) : 0.004초
## 2 소요시간(초.0f) : 0.042초
## 3 소요시간(초.0f) : 0.007초
100만
## 1 소요시간(초.0f) : 0.015초
## 2 소요시간(초.0f) : 0.063초
## 3 소요시간(초.0f) : 0.056초
## 1 소요시간(초.0f) : 0.015초
## 2 소요시간(초.0f) : 0.062초
## 3 소요시간(초.0f) : 0.058초
결과 1이 단순 for loop, 결과 2가 stream, 결과 3이 parallelStream 이다.
10만건이 되었든 100만건이 되었든... 단순 for loop가 빠르다.
이로 인해 내릴 수 있는 결론은 loop문 안에서 처리되는 비즈니스 로직에 block이나 delay 요소가 없다면 단순 for loop로 돌리는게 더 빠를 수 있다. stream이나 parallelStream은 list를 stream으로 바꾸고 내부적으로 라이브러리를 사용하는 비용이 소모 되므로 단순 작업에서는 더 느릴 수 있다고 어디선가 본 것 같다 ^^;;
그럼 loop문 안에 인위적으로 sleep을 넣는다면? 소스 코드 안의 sleep을 주석을 풀고 실행하게 되면 결과는 아래와 같다.
10만
## 1 소요시간(초.0f) : 1.001초
## 2 소요시간(초.0f) : 1.037초
## 3 소요시간(초.0f) : 0.144초
## 1 소요시간(초.0f) : 1.0초
## 2 소요시간(초.0f) : 1.077초
## 3 소요시간(초.0f) : 0.161초
100만
## 1 소요시간(초.0f) : 10.012초
## 2 소요시간(초.0f) : 10.09초
## 3 소요시간(초.0f) : 1.289초
## 1 소요시간(초.0f) : 10.004초
## 2 소요시간(초.0f) : 10.105초
## 3 소요시간(초.0f) : 1.291초
단순 for loop와 stream은 거의 차이가 없으며 parallelStream이 압도적으로 빠르다.
list를 parallelStream 으로 변환하고 라이브러리를 로드하고 사용하는 비용을 쓰더라도 loop문 안에서 지연이 발생해서 loop를 도는 속도가 현저히 떨어지게 된다면 병렬로 나눠 처리하는 것이 좋다는 결론을 얻게 된다.
하지만 loop 안에서 지연이 발생한다고 해서 무조건 parallelStream 을 쓰는 것이 좋을까?
경험 상 병렬로 작업을 처리한다 하더라도 loop 내부에 DB Insert, Update, Delete와 같은 것이 있다면 DB에 크나큰 부담으로 시스템 장애를 일으킬 수 있으니 조심해야 한다.
또한 parallelStream 이 CPU를 점유할 경우 다른 parallelStream 작업에도 영향을 미칠 수 있으므로 조심 ^^
덧. for loop보다 stream이 이론 상으로 더 빨라야 하는 것 같은데... 오히려 stream이 느리네..
stream이 더 빠른 경우가 무엇인지에 대한 고민이 필요 ^^;;
'Java' 카테고리의 다른 글
추상클래스와 인터페이스의 차이 (0) | 2021.02.08 |
---|---|
Java 기본 내용을 위한 북마크 (0) | 2021.01.28 |
RequestBody를 Enum 값에 Setting 할 때 생기는 문제 (0) | 2019.11.13 |
원격지의 이미지 파일을 읽어서 원하는 곳에 업로드 하기 (0) | 2017.02.09 |
MySQL의 zero date("0000-00-00 00:00:00") 값이 Date 값으로 넘어오지 않는 경우 (0) | 2015.04.06 |