@Configuration
@EnableAsync // 비동기 처리 기능 활성화
public class AsyncConfig {
... // 비동기 작업을 위한 스레드 풀 구성
}
@Service
@RequiredArgsConstructor
public class DataInitService {
@Async // 어노테이션 추가
public void createMemberAndPost(int memberIndex) {
... // 데이터 생성 로직
}
}
@Transactional
public void generateTestData() {
for (int i = 0; i < TOTAL_MEMBERS; i++) {
// 비동기 메서드 호출
dataInitService.createMemberAndPost(i);
}
}
기존 generateTestData() 코드
@Transactional
public void generateTestData() {
Random random = new Random();
// Member 객체 생성
for (int i = 1; i <= TOTAL_MEMBERS; i++) {
Member member = Member.builder()
.username("user" + memberIndex)
.password(passwordEncoder.encode("password" + memberIndex))
.email("user" + memberIndex + "@example.com")
.verified(true)
.paid(memberIndex % 2 == 0) // 유료회원과 일반회원의 비율은 1:1
.build();
memberService.save(member);
// Post 객체 생성 및 저장
boolean postPaid = member.isPaid(); // 멤버십 회원인 경우 유료글만 작성
int postNumber = (memberIndex - 1) * POSTS_PER_MEMBER + j + 1;
Post post = Post.builder()
.title("Post Title " + postNumber)
.body("Post Body " + postNumber)
.published(random.nextBoolean()) // 공개글 여부는 랜덤
.paid(postPaid)
.author(member)
.build();
postService.save(post);
}
}
@Configuration
@EnableAsync // 비동기 처리 기능 활성화
public class AsyncConfig { // 비동기 작업을 위한 스레드 풀 구성
@Bean(name = "threadPoolTaskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 항상 실행 중인 스레드의 최소 수 (CPU의 코어 수를 기반으로 설정)
executor.setMaxPoolSize(15); // 동시에 실행될 수 있는 최대 스레드 수 (코어 수의 2 ~ 4배가 일반적)
executor.setQueueCapacity(500); // 스레드 풀에서 처리될 때까지 대기하는 작업의 최대 수
executor.setThreadNamePrefix("Executor-"); // 의미 있는 이름 (디버깅 및 로깅 목적)
executor.initialize(); // 스레드 풀을 초기화 및 사용 준비
return executor;
}
}
@Service
@RequiredArgsConstructor
public class DataInitService {
private static final int POSTS_PER_MEMBER = 1; // 한 멤버가 작성할 글의 수
private final MemberService memberService;
private final PostService postService;
private final PasswordEncoder passwordEncoder;
@Async("threadPoolTaskExecutor") // 비동기 실행을 위해 해당 이름의 스레드 풀 사용
public void createMemberAndPost(int memberIndex) {
Random random = new Random();
// Member 객체 생성 및 저장
Member member = Member.builder()
.username("user" + memberIndex)
.password(passwordEncoder.encode("password" + memberIndex))
.email("user" + memberIndex + "@example.com")
.verified(true)
.paid(memberIndex % 2 == 0) // 멤버십 회원과 일반회원의 비율은 1:1
.build();
memberService.save(member);
// Post 객체 생성 및 저장
for (int j = 0; j < POSTS_PER_MEMBER; j++) {
boolean postPaid = member.isPaid(); // 멤버십 회원인 경우 유료글만 작성
int postNumber = (memberIndex - 1) * POSTS_PER_MEMBER + j + 1;
Post post = Post.builder()
.title("Post Title " + postNumber)
.body("Post Body " + postNumber)
.published(random.nextBoolean()) // 공개글 여부는 랜덤
.paid(postPaid)
.author(member)
.build();
postService.save(post);
}
}
}
@Configuration
@RequiredArgsConstructor
public class NotProd {
private final DataInitService dataInitService;
...
@Transactional
public void generateTestData() {
for (int i = 1; i <= TOTAL_MEMBERS; i++) {
// 비동기 메서드 호출 (데이터 처리를 위한 파라미터 전달)
dataInitService.createMemberAndPost(i);
}
}
회원 200명, 게시글 200개를 생성하는데 걸리는 시간
기존: 40초
비동기 처리 적용 후: 17초
*주의 사항
데이터 처리를 할 때 멀티스레딩을 사용하면 성능을 향상시킬 수 있지만, 동시성 문제를 일으킬 수가 있으므로 주의가 필요합니다.
ref.
https://akku-dev.tistory.com/89
https://cano721.tistory.com/208
https://dkswnkk.tistory.com/706