When I started with RxPY, I often run into the problem of missing a message when subscribing to an observable. This is especially true when working with the shared operator. This can be demonstrated by the following example, ...
import rx
from rx import operators as rx_op
from rx.concurrency import CurrentThreadScheduler
my_scheduler = CurrentThreadScheduler()
# create an shared observable emitting a single element "3"
shared_obs = rx.just(3, scheduler=my_scheduler) \
.pipe(rx_op.share())
# take the first element of the shared observable
left_obs = shared_obs.pipe(rx_op.first())
right_obs = shared_obs.pipe(rx_op.first())
# zip the two single element observables
out_obs = rx.zip(left_obs, right_obs)
out_obs.subscribe()
... which raises the following exception.
File "/home/mike/workspace/python/RxPY/rx/core/observer/autodetachobserver.py", line 45, in on_completed
self._on_completed()
File "/home/mike/workspace/python/RxPY/rx/core/operators/firstordefault.py", line 18, in on_completed
observer.on_error(SequenceContainsNoElementsError())
File "/home/mike/workspace/python/RxPY/rx/core/observer/autodetachobserver.py", line 35, in on_error
self._on_error(error)
File "/home/mike/workspace/python/RxPY/rx/core/observer/autodetachobserver.py", line 35, in on_error
self._on_error(error)
File "/home/mike/workspace/python/RxPY/rx/internal/basic.py", line 34, in default_error
raise err
rx.internal.exceptions.SequenceContainsNoElementsError: Sequence contains no elements
What happens?
- the
zip operator subscribes first left_obs observable
left_obs observable subscribes shared_obs observable
shared_obs observable subscribes just observable, which schedules the element "3" on the my_scheduler. Note that my_scheduler could also be a scheduler running on another thread. We then can not predict when the element "3" is exactly sent. In case of an "inactive" CurrentThreadScheduler, however, the element "3" is sent before subscribe method of the just observable returns.
- Element "3" is sent to
left_obs observer and then to zip observer
just observable completes
right_obs observable subscribes to shared_obs observable, but does not receive any elements, and therefore raises a SequenceContainsNoElementsError exception
The problem is that two different kind of actions (subscribing and emitting elements) are getting scheduled on the same scheduler. This leads to situations where it becomes almost impossible to determine, in which order actions are scheduled. And anyway, it should not be the responsibility of the RxPY user to keep track in which order subscriptions and emissions of elements happen.
Update: The problem is that the emission of elements are scheduled during the "subscribe" process. That way, the source observable might send (depending on the scheduler that is used) an element via on_next before all downstream observables subscribed to the source observable. Hence, some downstream observables will miss one or more elements.
My proposal is to extend the subscribe_ method with a third argument that represents the subscribe scheduler. The subscribe_ method of an Observable would then look as follows.
Update: Changed subscribe to subscribe_
def subscribe_(self, observer: Observer, scheduler: Scheduler, subscribe_scheduler: Scheduler):
""""
:param subscribe_scheduler: used to schedule "upstream" observables to start emitting their elements
:param scheduler: used to schedule the elements emitted by a source observable
""""
A subscribe_ makes sure that all "upstream" observables (e.g. observables connected to the observable that is getting subscribed to) are subscribed before the first element is emitted.
Another effect, is that the global variable current_thread_scheduler would become obsolete, because it is replaced by the "subscribe" scheduler.
When I started with RxPY, I often run into the problem of missing a message when subscribing to an observable. This is especially true when working with the
sharedoperator. This can be demonstrated by the following example, ...... which raises the following exception.
What happens?
zipoperator subscribes firstleft_obsobservableleft_obsobservable subscribesshared_obsobservableshared_obsobservable subscribesjustobservable, which schedules the element "3" on themy_scheduler. Note thatmy_schedulercould also be a scheduler running on another thread. We then can not predict when the element "3" is exactly sent. In case of an "inactive" CurrentThreadScheduler, however, the element "3" is sent beforesubscribemethod of thejustobservable returns.left_obsobserver and then tozipobserverjustobservable completesright_obsobservable subscribes toshared_obsobservable, but does not receive any elements, and therefore raises a SequenceContainsNoElementsError exceptionThe problem is that two different kind of actions (subscribing and emitting elements) are getting scheduled on the same scheduler. This leads to situations where it becomes almost impossible to determine, in which order actions are scheduled. And anyway, it should not be the responsibility of the RxPY user to keep track in which order subscriptions and emissions of elements happen.Update: The problem is that the emission of elements are scheduled during the "subscribe" process. That way, the source observable might send (depending on the scheduler that is used) an element via
on_nextbefore all downstream observables subscribed to the source observable. Hence, some downstream observables will miss one or more elements.My proposal is to extend the
subscribe_method with a third argument that represents the subscribe scheduler. Thesubscribe_method of anObservablewould then look as follows.Update: Changed
subscribetosubscribe_A
subscribe_makes sure that all "upstream" observables (e.g. observables connected to the observable that is getting subscribed to) are subscribed before the first element is emitted.Another effect, is that the global variable
current_thread_schedulerwould become obsolete, because it is replaced by the "subscribe" scheduler.