Reactor에서 `publishOn`과 `subscribeOn`의 역할
Reactor에서 publishOn
과 subscribeOn
의 역할
Spring WebFlux를 공부하기 위해서는 먼저 Reactor에 대해 이해하는 것이 중요하다. 특히, Reactor에서 제공하는 **publishOn
**과 **subscribeOn
**은 리액티브 스트림에서 중요한 개념이다. 이 두 가지 연산자는 비동기적으로 데이터 스트림을 처리하는 과정에서 스레드를 제어하는 역할을 한다. 이번 포스팅에서는 publishOn
과 subscribeOn
이 무엇인지, 그리고 어떻게 다르게 동작하는지에 대해 알아보자.
subscribeOn
이란?
**subscribeOn()
**은 말 그대로 구독 시점과 데이터 생성을 어느 스레드에서 실행할지를 결정하는 연산자다. 즉, 이 연산자가 적용되면 구독이 시작되는 순간부터 데이터가 생성되는 시점까지 특정 스레드에서 작업이 실행된다.
- 적용 시점: 체인의 어디에 위치하든 상관없이, 구독 시점부터 영향을 미친다.
- 영향 범위: 구독과 데이터 생성 전체에 영향을 미친다.
예시
Flux.just(1, 2, 3)
.subscribeOn(Schedulers.elastic()) // 구독과 데이터 생성이 elastic 스레드에서 실행됨
.map(data -> data * 2)
.subscribe(System.out::println);
위 예시에서는 subscribeOn(Schedulers.elastic())
이 설정되었기 때문에, Flux.just()
로 생성된 데이터는 elastic
스레드에서 처리된다. 즉, 데이터가 만들어지는 시점과 구독 시점이 elastic 스레드에서 실행된다는 뜻이다.
publishOn
이란?
**publishOn()
**은 조금 다르다. 이 연산자는 체인에서 호출된 이후의 연산자들이 어느 스레드에서 실행될지를 결정한다. 데이터 생성과 구독에는 영향을 미치지 않지만, 그 이후의 데이터 처리 과정에서 스레드 전환을 제어한다.
- 적용 시점: 이 연산자 이후의 모든 연산자에 영향을 미친다.
- 영향 범위:
publishOn()
호출 이후의 연산자들.
예시
Flux.just(1, 2, 3)
.map(data -> data * 2)
.publishOn(Schedulers.parallel()) // 이후의 작업은 parallel 스레드에서 실행됨
.subscribe(System.out::println);
이 코드에서는 데이터 생성은 기본 스레드에서 이루어지지만, publishOn(Schedulers.parallel())
이 호출된 이후의 연산은 parallel 스레드에서 실행된다. 즉, map()
과 subscribe()
는 parallel 스레드에서 처리된다.
subscribeOn
과 publishOn
의 차이점
둘의 차이점을 한 번에 정리하면 아래와 같다:
- 영향 범위:
subscribeOn()
: 구독과 데이터 생성 시점에 영향을 준다.publishOn()
: 호출된 이후의 연산자들에만 영향을 미친다.
- 위치에 따른 영향:
subscribeOn()
: 체인 어디에 위치하든, 첫 번째로 호출된 구독 시점에만 영향을 준다.publishOn()
: 이 연산자가 호출된 이후의 연산자들에만 스레드 전환을 적용한다.
- 여러 번 사용 가능 여부:
subscribeOn()
: 체인에서 한 번만 유효하다. 여러 번 호출해도 첫 번째로 설정된 스케줄러만 적용된다.publishOn()
: 여러 번 사용이 가능하며, 호출될 때마다 다른 스레드에서 실행되도록 설정할 수 있다.
subscribeOn
과 publishOn
을 함께 사용하면?
두 연산자를 함께 사용하면, 구독과 데이터 생성은 **subscribeOn()
**에서 설정한 스레드에서 실행되고, 이후의 연산은 **publishOn()
**에서 설정한 스레드에서 처리된다.
예시
Flux.just(1, 2, 3)
.subscribeOn(Schedulers.elastic()) // 구독과 데이터 생성은 elastic 스레드에서 실행됨
.publishOn(Schedulers.parallel()) // 이후의 연산은 parallel 스레드에서 실행됨
.map(data -> data * 2)
.subscribe(System.out::println);
위 코드에서는 구독과 데이터 생성은 elastic
스레드에서 실행되며, publishOn()
이후의 연산(map
, subscribe
)은 parallel
스레드에서 처리된다.
마무리
Spring WebFlux에서 리액티브 프로그래밍을 제대로 이해하려면, Reactor의 스레드 제어 방식인 **publishOn()
**과 **subscribeOn()
**을 제대로 이해해야 한다. **subscribeOn()
**은 구독과 데이터 생성 시점을 제어하고, **publishOn()
**은 그 이후의 작업 처리를 위한 스레드 제어를 담당한다. 이 두 가지를 적절히 사용하면, 비동기 작업을 효율적으로 분리하고 성능을 최적화할 수 있다.