Free Lines Arrow
본문 바로가기
Reactive Programing

[Reactive Programming] 속도비교

by skahn1215 2024. 11. 2.
728x90
반응형

속도비교

실제로 얼마나 속도차이가 나는지 blocking 코드와 reactor 코드를 비교해보자.

 

코드예제

고객에게 쿠폰을 발급하려고 한다.

 

조건은 가입일 5년 이상, 보유 포인트가 500 이상, 골드 멤버일 경우다.

걸리는 시간은 총 6초이다. 

 

isGoldMember: 골드 멤버인지 확인한다. 3초걸림.

isGreaterThan500point: 보유 포인트 확인. 2초 걸림

checkRegisterPeriod: 등록 기간 체크. 1초걸림.

package com.p8labs.reactive.compareCode;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Slf4j
@Service
public class CouponService {

    public boolean isGoldMember(Member member) throws InterruptedException {
        Thread.sleep(3000L);
        log.info("CHECK GRADE");
        return member.getGrade().equalsIgnoreCase("GOLD");
    }

    public boolean isGreaterThan500point(Member member) throws InterruptedException {
        Thread.sleep(2000L);
        log.info("CHECK POINT");
        return member.getPoint() >= 500;
    }

    public boolean checkRegisterPeriod(Member member) {
        try {
            Thread.sleep(1000L);
            log.info("CHECK PERIOD");
            LocalDate registerDate = member.getRegisterDttm().toLocalDate();
            LocalDate conditionDate = LocalDateTime.now().minusYears(5L).toLocalDate();
            return registerDate.isBefore(conditionDate) || registerDate.equals(conditionDate);
        } catch (Exception e) {
            return false;
        }
    }
}

 

Blocking

    public boolean blocking(Member member) {
        try {
            boolean checkRegisterPeriod = couponService.checkRegisterPeriod(member);
            boolean isGoldMember = couponService.isGoldMember(member);
            boolean isGreaterThan500point = couponService.isGreaterThan500point(member);
            return checkRegisterPeriod && isGoldMember && isGreaterThan500point;
        } catch (Exception e) {
            log.info("ERROR!!!!");
            return false;
        }
    }

 

결과

총 6초가 걸린다.

CHECK PERIOD
CHECK GRADE
CHECK POINT
걸린시간 6

 

 

Mono Blocking

    public Mono<Boolean> monoBlocking(Member member) {
        // 각 조건을 Flux로 변환하여 비동기 호출
        return Mono.zip(
                        Mono.fromCallable(() -> couponService.checkRegisterPeriod(member)),
                        Mono.fromCallable(() -> couponService.isGoldMember(member)),
                        Mono.fromCallable(() -> couponService.isGreaterThan500point(member))
                )
                .map(tuple -> {
                    Boolean isRegisterPeriodValid = tuple.getT1();
                    Boolean isGoldMemberValid = tuple.getT2();
                    Boolean isGreaterThan500pointValid = tuple.getT3();

                    // 모든 조건이 참인지 확인
                    return isRegisterPeriodValid && isGoldMemberValid && isGreaterThan500pointValid;
                });
    }

 

결과

리액터 코드로 작성했지만 결과가 blocking 과 동일하다.

이유는 쓰레드가 하나여서 쓰레드가 종료될때까지 기다렸고 그 결과
순차적으로 수행이 되었기 때문이다.

[    Test worker] c.p.reactive.compareCode.CouponService   : CHECK PERIOD
[    Test worker] c.p.reactive.compareCode.CouponService   : CHECK GRADE
[    Test worker] c.p.reactive.compareCode.CouponService   : CHECK POINT
걸린시간 6

 

 

Mono 에 Executor 적용하기

@Configuration
public class TaskExecutorConfig {

    private static final int TASK_QUEUE_CAPACITY = 100;
    private static final int KEEP_ALIVE_SECOND = 60;
    private static final String THREAD_NAME_PRFIX = "custom-";


    @Bean
    public Executor customExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); // 초기 스레드 수
        executor.setMaxPoolSize(50); // 최대 스레드 수
        executor.setQueueCapacity(100); // 대기열 크기
        executor.setThreadNamePrefix("CustomExecutor-");
        executor.initialize();
        return executor;
    }
}

 

 

subscribeOn(Schedulers.fromExecutor(customExecutor)) Executor를 =적용해주었다.

    public Mono<Boolean> mono(Member member) {
        // 각 조건을 Flux로 변환하여 비동기 호출
        return Mono.zip(
                        Mono.fromCallable(() -> couponService.checkRegisterPeriod(member))
                                .subscribeOn(Schedulers.fromExecutor(customExecutor)),
                        Mono.fromCallable(() -> couponService.isGoldMember(member))
                                .subscribeOn(Schedulers.fromExecutor(customExecutor)),
                        Mono.fromCallable(() -> couponService.isGreaterThan500point(member))
                                .subscribeOn(Schedulers.fromExecutor(customExecutor))
                )
                .map(tuple -> {
                    Boolean isRegisterPeriodValid = tuple.getT1();
                    Boolean isGoldMemberValid = tuple.getT2();
                    Boolean isGreaterThan500pointValid = tuple.getT3();

                    // 모든 조건이 참인지 확인
                    return isRegisterPeriodValid && isGoldMemberValid && isGreaterThan500pointValid;
                });
    }

 

결과

원하는대로 최대시간 3초가 걸렸다.

customExecutor1,2,3 쓰레드로 각각 함수가 수행이 되었다.

[customExecutor-1] c.p.reactive.compareCode.CouponService   : CHECK PERIOD
[customExecutor-3] c.p.reactive.compareCode.CouponService   : CHECK POINT
[customExecutor-2] c.p.reactive.compareCode.CouponService   : CHECK GRADE
걸린시간 3

 

 

 

결론

블록킹 코드와 비교하여 속도차이를 보았다. 

코드도 크게 달라지진 않았다.

중요한 점은 Mono 를 결합하여 쓸때는 반드시 여러개의 쓰레드에서 동작하는지
확인해보자.

728x90
반응형

'Reactive Programing' 카테고리의 다른 글

[Reactive Programming] zipWith  (0) 2024.11.09
[Reactive Programming] Flux, Mono 개념  (0) 2024.10.14
[Reactive Programming] 개념  (0) 2024.10.06

댓글