“직렬(Serial) 스케줄러와 병렬(Concurrent) 스케줄러”
Since schedulers can really be anything, and all operators that transform sequences need to preserve additional implicit guarantees, it is important what kind of schedulers are you creating.
스케줄러는 사실 어떤 형태로든 될 수 있으며, 시퀀스를 변환하는 모든 연산자는 추가적인 암시적 보장을 유지해야 하므로, 어떤 종류의 스케줄러를 생성하는지가 중요합니다.
scheduler 는 Rx에서 작업이 어디서 실행될지 결정하는 도구,
Swift에서 UI작업을 메인쓰레드에서 작동하고 데이터 다운로드/ 이미지처리을 백그라운드 쓰레드로 처리하듯이
직렬 스케쥴러(Serial Scheduler) / 병렬스케쥴러(Concurrent Scheduler) 가 존재하는것
In case the scheduler is concurrent, Rx's observeOn and subscribeOn operators will make sure everything works perfectly.
스케줄러가 병렬적인 경우, Rx의 observeOn 및 subscribeOn 연산자가 모든 작업이 완벽히 동작하도록 보장합니다.
보장해야한다?
Rx에서는 병렬작업을 처리할때 작업간 충돌이 발생하지 않도록 관리가 필요함 ( 두작업이 동시에 데이터를 수정하면 문제가 생길수 있음 )
그렇기때문에 Rx에서 observeOn / SubscribeOn을 통해서 작업의 실행환경을 제어함
subscribeOn으로 데이터 흐름의 시작점이 어떤스케쥴러에서 실행될지 설정 후
observeOn으로 데이터 흐름 중간 또는 끝에서 어떤 스케쥴러를 사용할지 설정.
Observable.just("Fetching Data")
.subscribeOn(Schedulers.io()) // 백그라운드 스레드에서 실행
.observeOn(MainScheduler.instance) // UI 스레드에서 결과 처리
.subscribe { print($0) }
If you use some scheduler that Rx can prove is serial, it will be able to perform additional optimizations.
Rx가 직렬 스케줄러임을 증명할 수 있는 경우, 추가적인 최적화를 수행할 수 있습니다.
직렬스케쥴러는 한번에 하나의 작업만으로 처리하므로, 작업간의 충돌/ 꼬임 을 걱정할필요가 없음
So far it only performs those optimizations for dispatch queue schedulers.
In case of serial dispatch queue schedulers, `observeOn` is optimized to just a simple dispatch_async call.
현재까지 이러한 최적화는 디스패치 큐 스케줄러에서만 수행됩니다. 직렬 디스패치 큐 스케줄러의 경우, observeOn은 단순한 dispatch_async 호출로 최적화됩니다.
직렬 디스패치 큐 에서 observeOn이 호출되면 복잡한 동작없이 간단히 dispatch_async를 호출하는 방식으로 최적화됩니다.
(이 하단부분은 이해를 하기에 시간이 오래걸릴것으로 예상되어서 따로 학습해보고 정리하려고 한다)
Besides current schedulers, you can write your own schedulers.
현재 Rx에서 제공하는 스케줄러 외에도, 사용자가 직접 스케줄러를 구현할 수 있습니다.
If you just want to describe who needs to perform work immediately, you can create your own scheduler by implementing the ImmediateScheduler protocol.
작업을 즉시 수행할 스케줄러를 정의하려면 ImmediateScheduler 프로토콜을 구현하여 커스텀 스케줄러를 만들 수 있습니다.
public protocol ImmediateScheduler {
func schedule<StateType>(
state: StateType,
action: (StateType) -> RxResult<Disposable>
) -> RxResult<Disposable>
}
If you want to create a new scheduler that supports time-based operations, then you’ll need to implement the Scheduler protocol.
시간 기반 작업을 지원하는 새로운 스케줄러를 만들고 싶다면 Scheduler 프로토콜을 구현해야 합니다.
public protocol Scheduler: ImmediateScheduler {
associatedtype TimeInterval
associatedtype Time
var now: Time { get }
func scheduleRelative<StateType>(
state: StateType,
dueTime: TimeInterval,
action: (StateType) -> RxResult<Disposable>
) -> RxResult<Disposable>
}
In case the scheduler only has periodic scheduling capabilities, you can inform Rx by implementing the PeriodicScheduler protocol.
스케줄러가 주기적인 작업을 지원한다면 PeriodicScheduler 프로토콜을 구현하여 Rx에 이를 알릴 수 있습니다.
public protocol PeriodicScheduler: Scheduler {
func schedulePeriodic<StateType>(
state: StateType,
startAfter: TimeInterval,
period: TimeInterval,
action: (StateType) -> StateType
) -> RxResult<Disposable>
}
In case the scheduler doesn’t support PeriodicScheduling capabilities, Rx will emulate periodic scheduling transparently.
스케줄러가 주기적인 작업을 지원하지 않는 경우, Rx는 이를 투명하게 에뮬레이션합니다.
Schedules units of work on the current thread. This is the default scheduler for operators that generate elements.
This scheduler is also sometimes called a “trampoline scheduler”.
If CurrentThreadScheduler.instance.schedule(state) { }is called for the first time on some thread, the scheduled action will be executed immediately and a hidden queue will be created where all recursively scheduled actions will be temporarily enqueued.
If some parent frame on the call stack is already running
CurrentThreadScheduler.instance.schedule(state) { }__, the scheduled action will be enqueued and executed when the currently running action and all previously enqueued actions have finished executing.
Abstracts work that needs to be performed on MainThread.
In case schedule methods are called from main thread, it will perform the action immediately without scheduling.
This scheduler is usually used to perform UI work.
Abstracts the work that needs to be performed on a specific dispatch queue t.
It will make sure that even if a concurrent dispatch queue is passed, it’s transformed into a serial one.
Serial schedulers enable certain optimizations for observeOn.
The main scheduler is an instance of SerialDispatchQueueScheduler.
Abstracts the work that needs to be performed on a specific dispatch queue t.
You can also pass a serial dispatch queue; it shouldn’t cause any problems.
This scheduler is suitable when some work needs to be performed in the background.
Abstracts the work that needs to be performed on a specific NSOperationQueue.
This scheduler is suitable for cases when there is some bigger chunk of work that needs to be performed in the background and you want to fine tune concurrent processing using maxConcurrentOperationCount.
[RxSwift] Implicit Observable Guarantees (3) | 2024.12.21 |
---|---|
[RxSwift] Disposing (2) | 2024.12.18 |
[RxSwift] Scheduler.1 (2) | 2024.12.12 |
[RxSwift] DesignRationale (3) | 2024.12.08 |
[RxSwift] Basic.2 (3) | 2024.11.29 |