// log main 1: sub2-3, number: 1 main 1: sub2-3, number: 2 main 1: sub2-3, number: 3 main 2: pub1-2, number: 1 main 2: pub1-2, number: 2 main 2: pub1-2, number: 3
subscribeOn
subscribeOn은 호출된 곳의 앞쪽 publisher 체인과 뒷쪽의 subscriber 체인을 한꺼번에 별도의 스레드로 분리한다.
느린 publisher 와 빠른 subscriber 의 조합에서 쓰기 적합하다고 하는데… 무슨 말인지 잘 모르겠다. 외부서비스에서 데이터를 읽어올때 쓰기 좋다고 한다.
위 예시처럼 subscribeOn을 동일한 체인에서 중첩해서 사용할 경우
첫번째 subscribeOn 앞뒤 체인을 묶어서 sub2 스케줄러에서 담당하고
두번째 subscribeOn 앞뒤 체인을 묶어서 sub1 스케줄러가 담당해야 하지만 이미 sub2에서 담당해서 그대로 sub2로 돌게 된다.
publishOn
publishOn은 호출된 곳의 앞쪽 publisher 체인은 그대로 두고 뒷쪽 subscriber 체인만 별도의 스레드로 분리한다.
빠른 publisher와 느린 subscriber 일때 쓰기 좋다고 하고 외부서비스로 데이터를 쓰는 작업할 때 좋닫고 한다.
위 예시에서 subscribeOn으로 sub2 스레드에서 돌다가 publishOn을 만나면서 pub1 스케줄러에 작업을 할당하고 나머지 연산을 진행한다.
리액티브 스트림 스펙은 리액티브 라이브러리가 서로 호환할 수 있게 해주며 여러 중요한 개선 사항이 많았지만 API 및 규칙만 정의하고 일상적인 사용을 위한 라이브러리는 제공하지 않았다.
리액티브 프레임워크중에서 가장 유명한 라이브러리 중 하나인 리액터 프로젝트(Project Reactor)는 1.x 버전에서 리액터 패턴, 함수형 프로그래밍 및 리액티브 프로그래밍과 같은 메시지 처리에 대한 모범 사례를 통합하여 비동기 논블로킹 처리를 지원하도록 설계하였다.
이후 여러 부족한 부분들을 보완하면서 2.x를 거쳐 현재는 3.x 버전으로 릴리즈되어있다.
리액터 프로젝트 필수 요소
비동기 파이프라인을 구축할 때 콜백 지옥과 깊게 중첩된 코드를 생략
코드 가독성을 높이고 리액터 라이브러리에 의해 정의된 워크플로에 **조합성(composability)**을 추가
리액터 API는 연산자를 연결해서 사용하는 것을 권장하며 이를 통해 복잡하고 재사용 가능한 실행 그래프(execution graph)를 작성할 수 있다.
그래프는 실행 흐름만 정의하며 구독자가 실제 구독을 했을 때만 데이터 플로가 기동된다.
오류 발생 가능성이 있는 비동기 요청의 결과를 효율적으로 처리하여 유연하지만 복원력 있는 코드를 작성할 수 있다.
리액티브 스트림 API는 Publisher가 생성하고 Subscriber가 소비한 모든 신호는 처리 중에 논블로킹이어야 하며 방해받지 않아야 한다고 규칙에 명시되어 있다.
모든 프로세서나 코어를 효율적으로 사용하려면 병렬처리가 필요하고 이는 일반적으로 onNext 메서드를 병렬로 호출하는 것을 뜻하지만 on*** 메서드의 호출은 스레드 안전성을 보장하는 방식으로 신호를 보내야 하며 다중 스레드에서 수행되는 경우 외부적인 동기화를 사용해야 한다. 즉, 스트림의 요소를 병렬 처리할 수 없다.
자원을 효율적으로 활용하기 위해 스트림 처리 파이프의 각 단계에 메시지를 비동기적으로 전달하는 것이다.
상황에 따라서 처리단계를 각각 별도의 스레드로 처리하고 각 스레드 사이에 큐와 같은 데이터 구조를 적용하여 메시지를 독립적으로 제공하고 사용하도록 할수 있다.