[RxSwift #3] Scheduler

2021. 9. 20. 11:17ReactiveX

스케쥴러는 작업을 어디서 수행할지에 관한 작업을 추상화한다. Main thread 에서 수행할지, background 에서 수행할지 등을 정할 수 있게 해준다. Rx를 사용하지 않아도 iOS 앱을 만들 때 작업을 어디에서 수행할지 정할 수 있었다.

 

DispatchQueue의 main은 작업을 main thread에서 수행하는 것을 의미했고, global은 백그라운드에서 수행하는 것을 의미했다. Dispatch queue뿐만 아니라 작업들을 수행하는 데에는 current thread, operation queues, new threads, thread pools, run loops 등이 사용된다. 이에 관한 글도 조만간 작성해야겠다^ㅛ^

 

RxSwift에서는 스케줄러를 통해 Observable을 생성하는 작업을 어디서 할지, 그리고 Observer가 시퀀스를 관찰하는 작업을 어디서 할지 정할 수 있다.

 

이 때 사용하는 연산자는 대표적으로 두 가지가 있는데, observeOn과 subscribeOn이다.

 

 

Scheduler operators

1. observeOn

Observer가 옵저버블을 어떤 쓰레드에서 관찰할지 설정할 수 있다. observeOn을 subscribeOn보다 많이 사용하게 된다고 한다. observeOn으로 쓰레드를 특별히 지정해주지 않으면, 현재 작업중인 곳에서 관찰 작업이 수행된다. 

 

let backgroundScheduler = ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global())

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

이 시퀀스는 관찰자가 background에서 관찰하도록 설정했다가, 다시 main 스케쥴러에서 관찰하도록 설정한 코드이다. 

 

 

2. subscribeOn

시퀀스를 생성하거나 dispose를 호출하는 작업을 수행할 쓰레드를 지정하고 싶으면 subscribeOn을 사용한다.

subscribeOn으로 쓰레드를 특별히 지정하지 않았다면 subscribe가 호출된 곳에서 작업이 수행될 것이다.

 

[RxSwift #0] 에서 언급했듯이 Observable이 선언된 후 실제 생성되는 시기는 subscribe를 호출했을 때이다. 따라서 subscribe가 호출되었다는 것은 시퀀스가 생성되었다는 의미이며, 시퀀스가 생성되는 위치를 subscribeOn을 통해 지정할 수 있다. 그래서 오퍼레이션의 이름이 subscribeOn인 듯하다.

 

다음과 같은 코드로 시퀀스 생성 쓰레드를 백그라운드로 설정할 수 있다.

let sequence2 = Observable<Int>.create { observer in
	observer.onNext(1)
    observer.onNext(2)
    
    return Disposables.create()
}

let bakckgroundScheduler = ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global())

sequence2
	.subscribeOn(bakckgroundScheduler)
    .subscribe(onNext : { print($0) })
    .disposed(by: disposeBag)

 

 

 

Serial vs Concurrent Schedulers

Serial scheduler는 background에서 작업을 처리하며, 일을 직렬적으로 처리한다. 반면 concurrent scheduler는 똑같이 background에서 작업을 처리하지만, 병렬적으로 여러 일을 동시에 처리한다.

 

Concurrent scheduler를 사용하면 Rx에서 observeOn과 subscribeOn을 사용할 때 모든 작업을 순조롭게 잘 처리할 수 있다. 하지만 Serial scheduler를 사용하고 싶다면 직렬적인 작업이라는 사실을 증명해야하기 때문에 observeOn은 Dispatch queue 중에서도 dispatch_async에서만 사용이 가능하다고 한다.

 

 

 

스케쥴러 종류

Main Scheduler

Main scheduler는 직렬적으로 작업을 수행시키는 serial scheduler이다. 메인 쓰레드에서 작업하며, 보통 UI 작업에 사용된다.

 

SerialDispatchQueueScheduler

이것 역시 직렬적으로 수행시키는 serial scheduler이며, concurrent dispatch queue로 할당에 실패했을 때, serial dispatch queue로 처리한다. Serial scheduler는 observeOn에 대해 최적화되어있다. 그리고 main scheduler도 이것의 인스턴스이다.

 

ConcurrentDispatchQueueScheduler

병렬적으로 작업을 수행시키는 스케쥴러이다. 작업을 background에서 수행시켜야 할 때 적합하다. 

 

OperationQueueScheduler

이것 역시 작업을 병렬적으로 수행시키는 스케쥴러이다. NSOperationQueue에서 수행되어야 하는 작업이 있을 때 이 스케쥴러를 사용한다. 백그라운드에서 처리해야하는 큰 작업이 있을 때 적합하다.