-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blocking zip operator #871
Conversation
RxJava-pull-requests #799 SUCCESS |
Definitively |
Thought so, started working on the question points anyway. |
Hey guys, |
RxJava-pull-requests #800 FAILURE |
signArchives failure again. |
Let's try again. |
RxJava-pull-requests #801 SUCCESS |
I am not sure where the main discussion is happening, so I am placing this response here. I looked at this because I am experimenting with rxcpp improvements and have been applying some of the choices made in RxJava. I was interested to see how this would map to C++ as well. My understanding is that that pause is called from onnext when the queue is filled to bufferSize. pause will block the stack that called onnext until resume is called. I saw some discussion about using SubscribeOn to prevent deadlocks. I was doing thought experiments of my own and wondered how that would be applied to Hot Observables? It seems like many Hot Observables have stacks rooted in threads that are dedicated to that source (UI thread, Sensor thread, IO thread) and that blocking those threads have consequences for the system. A UI thread would hang the app when blocked momentarily or deadlock if two UI events are being zipped. A Sensor thread might drop or queue readings for all the sensors being monitored or deadlock if two sensors readings are being zipped. Using SubscribeOn will not fix this and using ObserveOn only moves the infinite queue from zip to ObserveOn. I would suggest that a Hot Observable needs to be unsubscribed when the buffer is full. This sounds like ConnectableObservable is the surface that supports backpressure for HotObservables. I futher think that ColdObservables can be implemented using ConnectableObservable as well. speculation.. I also think that the buffering method, and depth and the backpressure algorithm should be unique to each source Observable. Thus, I am wondering if back-pressure can instead be implemented as overloads of a BackPressure operator that returns a ConnectableObservable and then all the operators that combine multiple observables have backpressure capable overloads that take only ConnectableObservable. Zip from N ConnectableObservables will have a fixed buffer depth of, for example, 1 and would thus start by calling Connect() on each source then unsubscribe the connect in the first onnext call from each source. When the onnext call is received from the last source the output onnext is called and then Connect() is called on each source - etc.. two examples of potential backpressure operators. A BlockingBackPressure operator would take Cold observables. It would block the source when it is disconnected and would take the Scheduler to use in SubscribeOn. No buffer needed. A LossyBackPressure operator would take hot observables and unsubscribe when the buffer is full and re-subscribe when the buffer has room. Critiques and explanations welcome. Thanks, |
This doesn't work. If you unsubscribe from range() then resubscribe later, range starts over again. If you unsubscribe from PublishSubject, you lose events. Ben reported about a new approach in #802 but no details. |
Of course, but some implementations of ConnectableObservable can block while others do not. You might not have read my whole comment. near the end you will find:
|
This seems like as good as any other place to try out the proposal. Here are the basics. Add three methods to Subscription: All of this will be coming in a day or two once cherry pick the changes from the prototype. |
Cool, can't wait to see the code :) I like the four operators, they make sense. I feel like one operation is missing from subscriber. How does Zip resume the subscribers? Additionally, one of the ways in which pause/isPaused are not like unsubscribe/isUnsubscribed is that pause will flip back and forth over time while unsubscribe is one-shot. This seems to introduce a few additional conditions that would need to be addressed: I am interested in the full semantics of a paused Subscriber.
This appears to force backpressure support in every source. This has tradeoffs between adoption and uniformity. Is there some pattern here that would allow opt in? Thanks, |
Zip resumes the inner subscribers internally when other subscriber has caught up by clearing the internal state that makes isPaused return true and then it invokes the actions passed in to resumeWith while it was paused. All actions passed in resumeWith are invoked when the subscriber is ready for more data. The second pause is treated the same as a second unsubscribe, probably ignored. Also actions passed in to resumeWith while not paused are immediately invoked. There is a lot of logic in the CompositeSubscription for handling all of this. These changes makes implementing Subscription directly very tricky. I'm inclined to try and make Subscription a final class and not an interface. That makes me wonder if there isn't something to the relationship between |
I like the idea that Subscriber is a concrete type, like Subject, and is a composition of Observer and Subscription. Thanks for the explanation. However, given those properties, why would pause be on the interface? Zip has to use private access to the Subscriber in order to resume, why not pause? Is there any case where a pause would be invoked outside Zip? |
I am also thinking that it would be a good idea to pass the scheduler that should be used to schedule the action to resumeWith. The Action supplied could have a call to schedule but I think it is important to be explicit, it allows the scheduler to be known and optionally overridden. Going with the Subject, Subscriber theme, perhaps resumeWith actually takes a Resumer that is a Scheduler and Action. Resumer may be a functor or have a named resume function that schedules the action. |
@abersnaze, I'm curious that how do you handle |
After experimenting with these approaches on For example, even I'll post another issue soon to pull the conversation together. |
Proposed solution to #867
Should I work on this case as well?Should it terminate as soon as possible?Update: