少し前に、RxSwift5のSchedulerの実装を読んでみたので、初めての読んだ系記事です。
概要
RxSwiftでは、observeOn
やsubscribeOn
で、流れてくるものに対する操作を行うスレッドやキューを指定できます。
それらの実行場所を指定するものがScheduler
クラス群になっていて、内部実装でDispatchQueue
やOperationQueue
をラップしています。
observeOnとsubscribeOn
observeOn
は、指定したschedulerで処理を実行するようなObservable
を返すメソッドです。
Observable.just(Thread.isMainThread) .map { _ in print(Thread.isMainThread) } .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) .subscribe(onNext: { print(Thread.isMainThread) }) .disposed(by: disposeBag)
このようにすると、observeOn
以降のprint
はDispatchQueue.global
で実行されるので、出力はtrue
、false
になります。
subscribeOn
はsubscribe
とその解除を指定したスケジューラーで行うようなObservable
を返すメソッドです。
Observable.just(Thread.isMainThread) .map { _ in print(Thread.isMainThread) } .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) .subscribe(onNext: { print(Thread.isMainThread) }) .disposed(by: disposeBag)
例えばこのように流すと、do
もサブスレッドで行われるため、出力は両方ともfalse
になります。
Serial/Concurrent Scheduler
ややこしいですが、Serial Scheduler(SerialDispatchQueueScheduler
)は並列なDispatchQueue
が渡された場合にも、実行順を保証するために、キューを直列に作り直します。
それに対して、Concurrent Schedulerは並列キューをそのまま実行してもに問題ない場合に用いられます。
こちらの場合、パフォーマンス的に有利になります。
主な組み込みのスケジューラー
MainScheduler
DispatchQueue.main
のラッパーになっているので、メインスレッドでasync
で実行されます。
しかし、これはSerialDispatchQueueScheduler
を実装しているので、直列スケジューラーです。
UIの更新などの、observeOn
向けの実装になっています。
ConcurrentMainScheduler
こちらもDispatchQueue.main
のラッパーですが、こちらは並列スケジューラーで、subscribeOn
用の実装になっています。
SerialDispatchQueueScheduler
DispatchQueue.global
のラッパーで直列スケジューラーです。
ConcurrentDispatchQueueScheduler
DispatchQueue.global
のラッパーで並列スケジューラーです。
グローバルキューなので、QoSを指定することが出来ます。
明示的にサブスレッドで動かしたい際は、通常こちらを利用することになります。