티스토리 뷰
● 도입
- Parallel Stream : 기존에 순차처리(Sequential) 하던 Stream을 병렬처리(Parallel) 하도록 만들어준다.
List<Integer> numbers = Arrays.asList(1, 2, 3);
Stream<Integer> parallelStream = numbers.parallelStream(); // 바로 병렬 Stream을 만들어준다.
Stream<Integer> parallelStream2 = numbers.stream().parallel(); // 기존의 Stream을 중간에 parallel로 바꾸는 것도 가능
[ Sequential(순차처리) vs Parallel(병렬처리) ]
- 여러개의 스레드를 이용하여 stream의 처리 과정을 병렬화(parallelize) = 여러개의 스레드를 이용하여 중간 처리들을 병렬로 처리한다.
- 중간 과정은 병렬 처리되지만 순서가 있는 Stream의 경우 종결 처리했을 때의 결과물이 기존의 순차적 처리와 일치하도록 종결 처리 과정에서 조정된다.
- 즉, 중간에 병렬 처리가 되어도 기존의 순서는 그대로 유지된다는 의미
ex) List로 collect 한다면 순서가 항상 올바르게 나온다는 것이다.
- 반면에 중간 처리의 과정은 뒤죽박죽이다.(여러 thread에서 실행되기 때문에), 마지막으로 모아주는 것만 순서대로 모아진다고 생각하면 된다.
[ 장단점 ]
장점
1. 굉장히 간단하게 병렬 처리를 사용할 수 있게 해준다.
2. 여러개의 스레드를 이용해 동시에 중간 처리를 하기 때문에 속도가 비약적으로 빨라질 수 있다.
단점
1. 항상 속도가 빨라지는 것은 아니다.
2. 공통으로 사용하는 리소스가 있을 경우 잘못된 결과가 나오거나 아예 오류가 날 수도 있다.(deadlock)
2-1. 이를 막기 위해 mutex, semaphore 등 병렬 처리 기술을 이용하면 오히려 순차 처리보다 느려질 수도 있다.
결론 : 작업을 할 때 Sequential(순차처리)과 Parallel(병렬처리) 중 어느게 더 적절한 지 고민을 한 후 사용해야한다.
● 실습
1. 검증되지 않은 유저를 골라내어 이메일을 보내자
- 이메일 발송 작업은 순서가 중요한 작업이 아니므로 바로 이럴때 병렬처리를 사용하면 좋다.
(메일 발송은 순서가 상관없기 때문)
package com.fastcampus.functionalprogramming.chapter8;
import java.util.Arrays;
import java.util.List;
import com.fastcampus.functionalprogramming.chapter8.model.User;
import com.fastcampus.functionalprogramming.chapter8.service.EmailService;
public class Chapter8Section10 {
public static void main(String[] args) {
User user1 = new User()
.setId(101)
.setName("Alice")
.setVerified(true)
.setEmailAddress("alice@fastcampus.co.kr");
User user2 = new User()
.setId(102)
.setName("Bob")
.setVerified(false)
.setEmailAddress("bob@fastcampus.co.kr");
User user3 = new User()
.setId(103)
.setName("Charlie")
.setVerified(false)
.setEmailAddress("charlie@fastcampus.co.kr");
User user4 = new User()
.setId(104)
.setName("David")
.setEmailAddress("david@fastcampus.co.kr")
.setVerified(true);
User user5 = new User()
.setId(105)
.setName("Eve")
.setEmailAddress("eve@fastcampus.co.kr")
.setVerified(false);
User user6 = new User()
.setId(106)
.setName("Frank")
.setEmailAddress("frank@fastcampus.co.kr")
.setVerified(false);
// TODO : 검증되지 않은 유저를 골라내어 이메일을 보내자
/*
* - 순서가 상관이 없는 작업을 한다면 parallelStream을 사용할 수 있다.
* - 이메일 발송 작업은 순서가 중요한 작업이 아니므로 바로 이럴때 병렬처리를 사용하면 좋다.
*/
// 순차처리
List<User> users = Arrays.asList(user1, user2, user3, user4, user5, user6);
long startTime = System.currentTimeMillis();
EmailService emailService = new EmailService();
users.stream()
.filter(user -> !user.isVerified())
.forEach(emailService::sendVerifyYourEmailEmail);
long endTime = System.currentTimeMillis();
System.out.println("Sequential(순차처리) : " + (endTime - startTime) + "ms");
// 순차처리는 처리 결과도 users List에 담긴 순서대로 처리된다.
// 병렬처리
List<User> users2 = Arrays.asList(user1, user2, user3, user4, user5, user6);
long startTime2 = System.currentTimeMillis();
EmailService emailService2 = new EmailService();
users2.stream().parallel()
.filter(user -> !user.isVerified())
.forEach(emailService2::sendVerifyYourEmailEmail);
long endTime2 = System.currentTimeMillis();
System.out.println("Parallel(병렬처리) : " + (endTime2 - startTime2) + "ms");
// 병렬처리는 users List에 담긴 순서대로 처리되지 않았다.
// 메일을 보내는 것은 순서가 상관없으니 병렬처리를 사용해도 문제없다.
}
}
- 순차처리는 메일 발송도 이름의 알파벳 순서대로 진행됐지만 병렬처리는 순서대로 진행되지 않았다.
2.
- 순서가 상관이 있는 작업을 한다면 parallelStream을 사용할 수 없다.
package com.fastcampus.functionalprogramming.chapter8;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.fastcampus.functionalprogramming.chapter8.model.User;
import com.fastcampus.functionalprogramming.chapter8.service.EmailService;
public class Chapter8Section10 {
public static void main(String[] args) {
User user1 = new User()
.setId(101)
.setName("Alice")
.setVerified(true)
.setEmailAddress("alice@fastcampus.co.kr");
User user2 = new User()
.setId(102)
.setName("Bob")
.setVerified(false)
.setEmailAddress("bob@fastcampus.co.kr");
User user3 = new User()
.setId(103)
.setName("Charlie")
.setVerified(false)
.setEmailAddress("charlie@fastcampus.co.kr");
User user4 = new User()
.setId(104)
.setName("David")
.setEmailAddress("david@fastcampus.co.kr")
.setVerified(true);
User user5 = new User()
.setId(105)
.setName("Eve")
.setEmailAddress("eve@fastcampus.co.kr")
.setVerified(false);
User user6 = new User()
.setId(106)
.setName("Frank")
.setEmailAddress("frank@fastcampus.co.kr")
.setVerified(false);
// 순서가 상관이 있는 작업을 한다면 parallelStream을 사용할 수 없다.
// TODO user의 이름을 대문자로 바꾼 후 (isVerified = true)로 설정하고 싶다.
/*
* 순서를 지켜야 하는 작업이다.
* 1. user의 이름을 대문자로 바꾼 후
* 2. (isVerified = true)로 설정하고 싶다.
*/
List<User> users3 = Arrays.asList(user1, user2, user3, user4, user5, user6);
// 아래의 작업은 users3 List에 담긴 순서와 상관 없이 실행될 때마다 순서가 뒤죽박죽으로 실행될 것이다.
List<User> processedUsers = users3.parallelStream()
.map(user -> {
System.out.println("Capitalize user name for user " + user.getId());
user.setName(user.getName().toUpperCase());
return user;
})
.map(user -> {
System.out.println("Set 'isVerified' to true for user " + user.getId());
user.setVerified(true);
return user;
})
.collect(Collectors.toList());
System.out.println("==================== 최종 결과물은 순서대로 출력 O ====================");
// 최종 결과물을 출력하는 아래의 코드는 users3 List에 담긴 순서대로 출력될 것이다.
for (User user : processedUsers) {
System.out.println("Name : " + user.getName() + " / isVerified : " + user.isVerified());
}
}
}
- 최종 결과물은 순서대로 출력되지만 중간 처리 과정은 매 실행 때마다 순서가 다르다는 것을 확인 할 수 있다.
'Backend > Java8' 카테고리의 다른 글
#35 함수형 프로그래밍 응용 - Lazy Evaluation(for 최적화) (0) | 2022.10.24 |
---|---|
#34 함수형 프로그래밍 응용 - Scope & Closure / Curry (0) | 2022.10.23 |
#32 Advanced Stream - forEach (0) | 2022.10.21 |
#31 Advanced Stream - Partitioning By (0) | 2022.10.20 |
#30 Advanced Stream - Grouping By (1) | 2022.10.19 |
- Total
- Today
- Yesterday
- spring
- 프로그래머스
- API
- SQL
- MySQL
- java
- 운영체제
- 알고리즘
- git
- Advanced Stream
- DART
- 빅데이터 분석기사
- Phaser
- Phaser3
- 자료구조
- SpringBoot
- nosql
- MongoDB
- Java8
- 코테
- OS
- 코딩테스트
- 메모리
- jpa
- node.js
- Stream
- Spring Boot
- 빅데이터
- 프로세스
- db
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |