상세 컨텐츠

본문 제목

[RxSwift] Scheduler.1

iOS/RxSwift

by kimrindev 2024. 12. 12. 21:10

본문

 

 Schedulers abstract away the mechanism for performing work.

 

Schedulers는 작업 수행 메커니즘을 추상화합니다.

추상화 하여 작업이 실행되는 위치(스레드, 큐 등)를 개발자가 명시적으로 선택할 수 있게 해줍니다.
RxSwift에서는 스레드 작업을 쉽게 관리하고, 비동기 로직을 간단히 작성할 수 있도록 도와줍니다.

 

Different mechanisms for performing work include the current thread, dispatch queues, operation queues, new threads, thread pools, and run loops.

 

작업을 수행하는 다양한 메커니즘은 다음과 같습니다:

  • 현재 스레드 (Current thread): 코드가 현재 실행되고 있는 스레드.
  • 디스패치 큐 (Dispatch queues):GCD(Grand Central Dispatch) 기반의 작업 큐.
  • 운영 큐 (Operation queues): Foundation의 OperationQueue를 사용한 스레드 관리.
  • 새로운 스레드 (New threads): 특정 작업을 처리하기 위해 새로 생성된 스레드.
  • 스레드 풀 (Thread pools): 여러 스레드를 재사용해 성능을 최적화하는 메커니즘.
  • 런 루프 (Run loops):  이벤트나 메시지를 처리하는 스레드 루프.

 

There are two main operators that work with schedulers, observeOn and subscribeOn.
If you want to perform work on a different scheduler just use observeOn(scheduler) operator.
You would usually use observeOn a lot more often than subscribeOn.

 

Schedulers와 관련된 두 가지 주요 연산자는 observeOn과 subscribeOn입니다.

다른 Scheduler에서 작업을 수행하고 싶다면, observeOn(scheduler) 연산자를 사용하면 됩니다.

보통 observeOn을 subscribeOn보다 훨씬 더 자주 사용합니다.

 

observeOn:

  • 이후의 작업이 특정 Scheduler에서 실행되도록 지정합니다.
  • 데이터 흐름의 중간 단계에서 Scheduler를 변경할 때 사용합니다.

subscribeOn:

  • 데이터 흐름의 처음 단계에서 작업을 실행할 Scheduler를 지정합니다.
  • 한 번만 설정되며, 이후 데이터 흐름에는 영향을 미치지 않습니다.

observeOn의 중요성

  • observeOn을 더 자주 사용하는 이유는 보통 데이터 흐름 중간에 스레드를 변경하는 요구가 더 많기 때문입니다.
  • 예를 들어, 네트워크 요청은 백그라운드 스레드 에서 실행하고, UI 업데이트는 메인 스레드에서 실행해야 합니다.

In case observeOn isn't explicitly specified, work will be performed on whichever thread/scheduler elements are generated.

 

만약 observeOn 이 명시적으로 지정되지 않으면, 작업은 요소가 생성된 스레드/스케줄러에서 수행됩니다.

 

observeOn이 없는 경우

  • observeOn이 명시적으로 설정되지 않으면, 작업은 데이터를 생성하는 스레드에서 실행됩니다.
  • 작업 흐름이 한 스레드에서만 실행될 수 있으므로 비효율적이거나 UI 스레드에서 부하가 발생할 수 있습니다.
Example of using the observeOn operator:

 

sequence1
  .observeOn(backgroundScheduler)
  .map { n in
      print("This is performed on the background scheduler")
  }
  .observeOn(MainScheduler.instance)
  .map { n in
      print("This is performed on the main scheduler")
  }

 

If you want to start sequence generation (subscribe method) and call dispose on a specific scheduler, use subscribeOn(scheduler).

 

시퀀스 생성(구독 메서드 시작) 및 dispose를 특정 스케줄러에서 호출하려면 subscribeOn(scheduler)을 사용하세요.

 

In case subscribeOn isn’t explicitly specified, the subscribe closure (closure passed to Observable.create) will be called on the same thread/scheduler on which subscribe(onNext:) or subscribe is called.

 

subscribeOn이 명시적으로 지정되지 않은 경우, 구독 클로저(Observable.create에 전달된 클로저)는 subscribe(onNext:) 또는 subscribe가 호출된 동일한 쓰레드/스케줄러에서 실행됩니다

 

In case subscribeOn isn’t explicitly specified, the dispose method will be called on the same thread/scheduler that initiated disposing.

 

subscribeOn이 명시적으로 지정되지 않은 경우, dispose 메서드는 disposing을 시작한 동일한 쓰레드/스케줄러에서 호출됩니다.”

 

In short, if no explicit scheduler is chosen, those methods will be called on current thread/scheduler.

 

“요약하면, 명시적으로 스케줄러가 지정되지 않으면 해당 메서드들은 현재 쓰레드/스케줄러에서 호출됩니다.”

 

observable
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // 1. 백그라운드 쓰레드에서 생성
    .map { data in
        print("백그라운드 쓰레드에서 데이터 처리 중")
        return processData(data) // 2. 데이터를 가공
    }
    .observeOn(MainScheduler.instance) // 3. 메인 쓰레드로 전환
    .map { processedData in
        print("메인 쓰레드에서 UI 작업 실행 중")
        updateUI(with: processedData) // 4. UI 업데이트
    }
    .observeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // 5. 다시 백그라운드 쓰레드로 전환
    .map { processedData in
        print("백그라운드에서 추가 데이터 처리 중")
        return furtherProcessing(processedData) // 6. 추가 데이터 처리
    }
    .subscribe(onNext: { finalData in
        print("최종 데이터: \(finalData)")
    })
    .disposed(by: disposeBag)

 

let observable = Observable.create { observer in
    // 데이터 생성 작업 (예: 네트워크 호출, 파일 읽기 등)
    let data = fetchData()
    observer.onNext(data)  // 데이터 전달
    observer.onCompleted()
    return Disposables.create()
}

// 1. 백그라운드 쓰레드에서 Observable 생성
observable
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
    
    // 2. 필요한 데이터를 가공하거나 변환 (여전히 백그라운드 쓰레드에서 실행)
    .map { data in
        return processData(data)  // 데이터 가공
    }
    
    // 3. 메인 쓰레드로 전환하여 UI 업데이트
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { processedData in
        // UI 업데이트 (메인 쓰레드에서 실행)
        updateUI(with: processedData)
    })
    .disposed(by: disposeBag)

 

 


why? (observable- create/dispose 는 subscribeOn(백그라운드쓰레드)) 일까

create의 단계에서는 네트워크 요청,  데이터베이스 읽기/쓰기,  파일 입출력,  CPU 집약적인 계산 을 포함할수 있음 

dispose의 단계에서는 네트워크 요청 취소, 파일 쓰기 중단, 메모리 해제, 백그라운드 작업 취소 가 포함될수 있음 

 

이러한 작업들은 보통 시간이 오래걸릴수 있으며,메인쓰레드에서 실행되면 UI가 멈추거나 앱의 반응성이 떨어질수 있음

즉 백그라운드 쓰레드에서 실행해야 앱의성능을 유지할수 있음

 

 

그리고 observeOn으로 쓰레드를 스위칭할수있도록 처리함 
eg) mainThread -> backgroundThread, backgroundThread -> mainThread 


스케줄러를 지정하지 않은 경우의 동작:

  •  subscribeOn이나 observeOn이 없으면, 다음 작업들이 모두 **현재 스레드/스케줄러**에서 실행됩니다:
  •  Observable 생성 작업.
  •  데이터 스트림의 변환(map, filter 등)과 소비(onNext 등) 작업.
  •  dispose 작업.

 이는 작은 애플리케이션에서는 문제가 없을 수 있지만, UI 스레드에서 복잡한 작업이 실행되면 성능 문제가 발생할 수 있습니다.

 

 RxSwift에서 스케줄러를 활용하는 방식은 작업의 성격과 목적에 따라 적절히 분리해서 사용하는 것이 핵심
Observable 생성 작업은 subscribeOn으로 백그라운드에서 처리

 

 

subscribeOn과 observeOn의 역할 분리

  •  subscribeOn: Observable 생성과 Dispose 작업을 수행할 스레드 지정.
  •  주로 Observable 시작 시점의 작업에 영향을 줌.
  •  observeOn: 방출된 데이터의 처리 흐름 중간에 스레드 전환.
  •  데이터 가공, UI 업데이트, 네트워크 요청 등 중간 작업의 실행 스레드를 제어.

'iOS > RxSwift' 카테고리의 다른 글

[RxSwift] Disposing  (2) 2024.12.18
[RxSwift] Scheduler.2  (1) 2024.12.16
[RxSwift] DesignRationale  (3) 2024.12.08
[RxSwift] Basic.2  (3) 2024.11.29
[RxSwift] Basic.1  (1) 2024.11.28

관련글 더보기