Reactor에서 publishOnsubscribeOn의 역할

Spring WebFlux를 공부하기 위해서는 먼저 Reactor에 대해 이해하는 것이 중요하다. 특히, Reactor에서 제공하는 **publishOn**과 **subscribeOn**은 리액티브 스트림에서 중요한 개념이다. 이 두 가지 연산자는 비동기적으로 데이터 스트림을 처리하는 과정에서 스레드를 제어하는 역할을 한다. 이번 포스팅에서는 publishOnsubscribeOn이 무엇인지, 그리고 어떻게 다르게 동작하는지에 대해 알아보자.

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 스레드에서 처리된다.

subscribeOnpublishOn의 차이점

둘의 차이점을 한 번에 정리하면 아래와 같다:

  1. 영향 범위:
  • subscribeOn(): 구독과 데이터 생성 시점에 영향을 준다.
  • publishOn(): 호출된 이후의 연산자들에만 영향을 미친다.
  1. 위치에 따른 영향:
  • subscribeOn(): 체인 어디에 위치하든, 첫 번째로 호출된 구독 시점에만 영향을 준다.
  • publishOn(): 이 연산자가 호출된 이후의 연산자들에만 스레드 전환을 적용한다.
  1. 여러 번 사용 가능 여부:
  • subscribeOn(): 체인에서 한 번만 유효하다. 여러 번 호출해도 첫 번째로 설정된 스케줄러만 적용된다.
  • publishOn(): 여러 번 사용이 가능하며, 호출될 때마다 다른 스레드에서 실행되도록 설정할 수 있다.

subscribeOnpublishOn을 함께 사용하면?

두 연산자를 함께 사용하면, 구독과 데이터 생성은 **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()**은 그 이후의 작업 처리를 위한 스레드 제어를 담당한다. 이 두 가지를 적절히 사용하면, 비동기 작업을 효율적으로 분리하고 성능을 최적화할 수 있다.