Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should subscribeOn and observeOn only be invoked by the final subscriber?

The Scheduling and Threading section of Intro to Rx says that

the use of SubscribeOn and ObserveOn should only be invoked by the final subscriber

It also says that in an UI application, the presentation layer, which is normally the final subscriber, should be the one to invoke these methods.

I am wondering if the advice is solid, since I see some situations in which this is not convenient:

  1. For starters, I don't believe that the presentation layer should decide where an Observable coming from the data layer should be subscribed. In my opinion, the presentation layer should be unaware if the data is coming from a database, from a REST API, or from memory. For this reason, it's convenient for the data layer to call subscribeOn() before returning the Observable, passing the IO Scheduler or the immediate Scheduler as convenient.
  2. If the presentation layer gets the Observable from some service or use case (which in turn gets it from the data layer) and this service decides that it needs to process the stream in some computation Scheduler, why should the presentation layer care about this?
  3. What about a stream that is originally coming from the UI, so it needs to be subscribed in the UI thread. Then it will be sent to some service to do some work and finally come back to the presentation layer to be observed in the UI thread. That would require the UI stream to be subscribeOn() the UI Scheduler, then observeOn() some other Scheduler, and finally observeOn() the UI Scheduler. In this case, being able to invoke subscribeOn() and observeOn() only in the final subscriber would mean that the stream can only be processed in the UI thread.

Is there some good reason why I should sacrifice the architecture of my application and ignore Rx's ability to easily switch threads by invoking these two methods only by the final subscriber?

like image 657
sorianiv Avatar asked Jan 08 '16 10:01

sorianiv


People also ask

What is the difference between subscribeOn and observeOn?

The subscribeOn works upstream so the first map is in computation thread. The first observeOn was able to change the thread to IO thread and the second observeOn changed it to Main thread. The final subscribeOn is unable to change the thread set by observeOn. observeOn works only downstream.

What is observeOn?

observeOn() observeOn controls which schedulers is used in downstream subscribers. Any code inside create is controlled by subscribeOn, now we might need to do a task in a background thread and update the UI thread after this. This is the most common use case in android development, observeOn comes to the rescue.

Why schedulers and how RxJava internally works with them?

RxJava Schedulers. Threading in RxJava is done with help of Schedulers. Scheduler can be thought of as a thread pool managing 1 or more threads. Whenever a Scheduler needs to execute a task, it will take a thread from its pool and run the task in that thread.

Is RxJava single threaded?

2. Default Threading Behavior. By default, Rx is single-threaded which implies that an Observable and the chain of operators that we can apply to it will notify its observers on the same thread on which its subscribe() method is called.


2 Answers

Great to see you have read the book and are taking the time to challenge some of the guidance there.

The reason I give this guidance is because

  1. Concurrency is hard, and having a simple rule helps teams produce better code
  2. Concurrency is hard, and having a single place to locate your concurrency concerns allows for a better mental model of your stack/layering and should simplify testing. The more layers that introduce concurrency in your application, the worse
  3. Blocking the UI thread is not good news. Getting off the UI-Thread asap, and then delaying any processing of data back on the UI as late as possible is preferable. This pattern aims to serve that goal.

These are obviously my opinions but I have seen these simple guidelines help clean up code on dozens of projects, reduce code bases, improve test ability, improve predictability and in numerous case massively improve performance.

Sadly, it is difficult to put together case studies of these projects as most of them are protected by NDAs.

I would be keen to see how it works for you or how you apply an alternate pattern.

like image 167
Lee Campbell Avatar answered Sep 21 '22 12:09

Lee Campbell


  1. The presentation layer doesn't care where the observable comes from, per se, but it does care if it might lock up the UI thread. So the presentation layer must take precautions to prevent that from happening. This is a case of blissful ignorance with a layer of safety.

  2. The presentation layer doesn't care. It only wants to make sure it itself is not blocked.

  3. If the stream comes from the UI and it takes a lengthy time to process then the owner of the stream should be conscientious of this and make sure that it is processed on a non-UI scheduler. Then the UI has to make sure it comes back to the UI thread if it needs to be consumed there. If the processing is fast then it doesn't matter.

like image 38
Enigmativity Avatar answered Sep 19 '22 12:09

Enigmativity