RxJava 스케줄러의 사용 사례


253

RxJava에는 5 가지 스케줄러 가 있습니다 :

  1. instant () : 현재 스레드에서 즉시 작업을 실행하는 스케줄러를 만들고 반환합니다.

  2. trampoline () : 현재 작업이 완료된 후 실행될 현재 스레드에서 작업을 대기시키는 스케줄러를 작성하고 리턴합니다.

  3. newThread () : 작업 단위마다 새 스레드를 작성하는 스케줄러를 작성하고 리턴합니다.

  4. calculation () : 계산 작업을위한 스케줄러를 만들고 반환합니다. 이벤트 루프, 콜백 처리 및 기타 계산 작업에 사용할 수 있습니다. 이 스케줄러에서 IO 바운드 작업을 수행하지 마십시오. 스케줄러를 사용하십시오. 대신 io () .

  5. io () : IO 바운드 작업을위한 스케줄러를 생성하고 반환합니다. 구현은 필요에 따라 확장되는 Executor 스레드 풀에 의해 지원됩니다. 이는 차단 IO를 비동기 적으로 수행하는 데 사용할 수 있습니다. 이 스케줄러에서 계산 작업을 수행하지 마십시오. 스케줄러를 사용하십시오. calculation () 대신에.

질문 :

처음 3 개의 스케줄러는 설명이 필요 없습니다. 그러나 나는 계산io 에 대해 약간 혼란 스럽다 .

  1. "IO 바운드 작업"이란 정확히 무엇입니까? 스트림 ( java.io) 및 파일 ( java.nio.files) 을 처리하는 데 사용 됩니까? 데이터베이스 쿼리에 사용됩니까? 파일을 다운로드하거나 REST API에 액세스하는 데 사용됩니까?
  2. 어떻게 계산 () 다른 newThread는 () ? 모든 계산 () 호출이 매번 새로운 (배경) 스레드 대신 단일 (배경) 스레드에 있습니까?
  3. IO 작업을 수행 할 때 calculation () 을 호출 하는 것이 왜 나쁜 가요?
  4. 계산 작업을 수행 할 때 io () 를 호출하는 것이 왜 나쁜 가요?

답변:


332

좋은 질문은 설명서가 더 자세하게 할 수 있다고 생각합니다.

  1. io()제한되지 않은 스레드 풀에 의해 지원되며 계산에 집중적이지 않은 작업, 즉 CPU에 많은 부하를주지 않는 작업에 사용하는 일종입니다. 따라서 파일 시스템과의 상호 작용, 다른 호스트의 데이터베이스 또는 서비스와의 상호 작용이 좋은 예입니다.
  2. computation()사용 가능한 프로세서 수와 동일한 크기의 바운드 스레드 풀이 지원합니다. 가용 프로세서 이상 (예 :)을 사용하여 CPU 집약적 인 작업을 병렬로 예약하려고하면 newThread()스레드가 프로세서를 처리 할 때 스레드 생성 오버 헤드 및 컨텍스트 전환 오버 헤드가 발생하고 성능이 크게 저하 될 수 있습니다.
  3. computation()CPU 집약적 인 작업 을 떠나는 것이 가장 좋습니다. 그렇지 않으면 CPU 사용률이 좋지 않습니다.
  4. io()2에서 논의한 이유 때문에 계산 작업 을 요구 하는 것은 좋지 않습니다. io()그리고 수천 개의 계산 작업을 io()동시에 예약하면 해당 천 개의 작업 각각에 고유 한 스레드가 있고 상황 전환 비용을 발생시키는 CPU와 경쟁하게됩니다.

5
RxJava 소스에 익숙 함 그것은 오랫동안 저에게 혼란의 원천이었습니다.이 점에서 문서가 강화되어야한다고 생각합니다.
Dave Moten

2
@ IgorGanapolsky 나는 당신이 거의하고 싶지 않은 것 같아요. 스레드는 구성 및 해체 비용이 비싸므로 모든 작업 단위에 대해 새 스레드를 작성하는 것이 효율성에 거의 도움이되지 않습니다. 일반적으로 계산 () 및 기타 스케줄러가 수행하는 스레드를 재사용하려고합니다. newThread ()가 합법적 인 사용 (적어도 내가 생각할 수있는)을 가질 수있는 유일한 시간은 격리되고 자주 실행되지 않는 작업을 시작하는 것입니다. 그럼에도 불구하고 그 시나리오에 io ()를 사용할 수 있습니다.
tmn

4
trampoline ()이 유용한 예제를 보여 주시겠습니까? 개념을 이해했지만 실제로 사용할 시나리오를 파악할 수 없습니다. ID가 여전히 나에게 미스터리 인 유일한 스케줄러입니다.
tmn

32
네트워크 호출의 경우 Schedulers.io ()를 사용하고 동시 네트워크 호출 수를 제한해야하는 경우 Scheduler.from (Executors.newFixedThreadPool (n))을 사용하십시오.
Dave Moten

4
timeout기본적으로 computation()스레드를 차단 한다고 생각할 수도 있지만 그렇지 않습니다. 내부적으로 computation()사용 ScheduledExecutorService지연 행동을 차단하지 않도록 시간을. computation()다른 스레드에있는 경우 스레드 전환 비용 이 발생하기 때문에이 사실을 고려 하는 것이 좋습니다.
Dave Moten

3

가장 중요한 점은 Schedulers.ioSchedulers.computation 이 모두 질문에 언급 된 다른 스레드와 달리 무제한 스레드 풀에 의해 뒷받침된다는 것입니다. 이 특성은 ExecutornewCachedThreadPool (자동 교정 스레드 풀과 제한되지 않음) 로 작성되는 경우 에만 Schedulers.from (Executor) 에 의해 공유됩니다 .

이전 답변과 웹의 여러 기사에서 풍부하게 설명했듯이 Schedulers.ioSchedulers.computation 은 이름의 작업 유형에 최적화되어 있으므로 신중하게 사용해야합니다. 그러나 내 견해로는 가장 중요한 역할은 반응 스트림에 실제 동시성을 제공하는 것 입니다.

새로 온 사람들의 신념과는 달리, 반응성 스트림은 본질적으로 동시적인 것이 아니라 본질적으로 비동기적이고 순차적입니다. 이러한 이유로 Schedulers.io 는 I / O 작업이 차단 된 경우에만 사용되어야합니다 (예 : Apache IOUtils FileUtils.readFileAsString (...) 과 같은 차단 명령 사용 ). 끝난.

Java AsynchronousFileChannel (...)과 같은 비동기 메소드를 사용하면 조작 중에 호출 스레드를 차단하지 않으므로 별도의 스레드를 사용할 필요가 없습니다. 실제로 Schedulers.io 스레드는 이벤트 루프를 실행하지 않고 콜백이 호출되지 않기 때문에 실제로 비동기 작업에 적합하지 않습니다.

데이터베이스 액세스 또는 원격 API 호출에도 동일한 논리가 적용됩니다. Schedulers.io를 사용하지 마십시오비동기식 또는 반응 형 API를 사용하여 호출 할 수있는 경우 .

동시성으로 돌아갑니다. 비동기식 또는 반응 형 API에 액세스하여 I / O 작업을 비동기식 또는 동시에 수행하지 못할 수 있으므로 유일한 대안은 별도의 스레드에서 여러 호출을 디스패치하는 것입니다. 아아, 반응성 스트림은 끝에서 순차적 하지만 좋은 소식은 있다는 것입니다 flatMap () 운영자가 자신의 핵심에 동시성을 도입 할 수 있습니다 .

동시성은 일반적으로 flatMap () 연산자를 사용하여 스트림 구성에 빌드되어야합니다 . 이 강력한 연산자는 flatMap () 내장 Function <T, R>에 멀티 스레드 컨텍스트를 내부적으로 제공하도록 구성 할 수 있습니다 . 해당 컨텍스트는 Scheduler.io 또는 Scheduler.computation 과 같은 다중 스레드 스케줄러에 의해 제공됩니다 .

RxJava2 스케줄러동시성 에 대한 기사에서 스케줄러를 순차적으로 동시에 사용하는 방법에 대한 코드 샘플 및 자세한 설명을 찾을 수 있습니다.

도움이 되었기를 바랍니다,

소프트 제이크


2

이 블로그 게시물은 훌륭한 답변을 제공합니다

블로그 게시물에서 :

Schedulers.io () 는 무제한 스레드 풀에 의해 지원됩니다. 파일 시스템과의 상호 작용, 네트워크 호출 수행, 데이터베이스 상호 작용 등을 포함하여 CPU를 많이 사용하지 않는 I / O 유형 작업에 사용됩니다.이 스레드 풀은 비동기식으로 IO 차단을 수행하기 위해 사용됩니다.

Schedulers.computation () 은 사용 가능한 프로세서의 수까지 크기가있는 경계 스레드 풀에 의해 지원됩니다. 이미지 크기 조정, 대용량 데이터 세트 처리 등과 같은 계산 또는 CPU를 많이 사용하는 작업에 사용됩니다.주의 : 사용 가능한 코어보다 많은 계산 스레드를 할당하면 컨텍스트 전환 및 스레드 생성 오버 헤드로 인해 성능이 저하됩니다. 프로세서의 시간.

Schedulers.newThread () 각 작업 단위에 대해 새 스레드를 작성합니다. 이 스케줄러는 매번 새 스레드가 생성되고 재사용이 발생하지 않으므로 비용이 많이 듭니다.

Schedulers.from (Executor executor) 은 지정된 실행 프로그램이 지원하는 사용자 정의 스케줄러를 작성하고 리턴합니다. 스레드 풀의 동시 스레드 수를 제한하려면 Scheduler.from (Executors.newFixedThreadPool (n))을 사용하십시오. 이렇게하면 모든 스레드가 점유 될 때 작업이 예약되면 대기열에있게됩니다. 풀의 스레드는 명시 적으로 종료 될 때까지 존재합니다.

메인 스레드 또는 AndroidSchedulers.mainThread () 는 RxAndroid 확장 라이브러리에서 RxJava로 제공됩니다. 메인 스레드 (UI 스레드라고도 함)는 사용자 상호 작용이 발생하는 위치입니다. 응답하지 않는 응답 성이없는 UI 또는 ANR (Application Not Responding) 대화 상자를 방지하기 위해이 스레드를 오버로드하지 않도록주의해야합니다.

Schedulers.single () 은 RxJava 2의 새로운 기능입니다.이 스케줄러는 요청 된 순서대로 작업을 순차적으로 실행하는 단일 스레드에 의해 지원됩니다.

Schedulers.trampoline () 은 참여하는 작업자 스레드 중 하나에 의해 FIFO (선입 선출) 방식으로 작업을 실행합니다. 호출 스택 증가를 피하기 위해 재귀를 구현할 때 자주 사용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.