RxJava2.0 (5) back pressure strategy

In the previous section, we found the source of the unbalanced upstream and downstream flow rates. In this section, we will learn how to deal with it. Many friends who have read articles written by other people may think that only the solution can be solved, so everyone Flowableagrees This Flowablehas great expectations.

Let’s put it aside today Flowableand just rely on our own 双手和智慧to see how we govern. After studying this section, we will look at it again Flowable, and you will find that it is not as awesome as you imagined, it is just overly deified by others up.

topic

Let's look at this example from the previous section:

Observable.create(new ObservableOnSubscribe<Integer>() {
     @Override
     public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
          for (int i = 0; ; i++) {  //无限循环发送事件
               emitter.onNext(i);
          }
     }
 }).subscribeOn(Schedulers.io())
   .observeOn(AndroidSchedulers.mainThread())
   .subscribe(new Consumer<Integer>() {
          @Override
          public void accept(Integer integer) throws Exception {
               Log.d(TAG, "" + integer);
          }
 });

In the previous section, we saw that the result of its operation is that it directly exploded the memory, and we also understand why it exploded the memory, so what can we do to prevent this from happening.

As we said before, all the events sent upstream are put into the water tank, so the water tank is full in an instant, then we can only put the events we need into the water tank, and only put part of the data into the water tank. Will it not overflow in this way, so let's modify the above code:

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        for (int i = 0; ; i++) {
             emitter.onNext(i);
        }
    }
}).subscribeOn(Schedulers.io())
  .filter(new Predicate<Integer>() {
      @Override
      public boolean test(Integer integer) throws Exception {
          return integer % 10 == 0;
      }
}).observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<Integer>() {
      @Override
      public void accept(Integer integer) throws Exception {
          Log.d(TAG, "" + integer);
      }
});

In this code, we have added a filter to only allow events divisible by 10 to pass through, and then look at the running results:

It can be seen that although the memory is still increasing, the growth rate has been reduced too much compared to before. At least the memory has not exploded before I finished recording the GIF. You can try to change it to be divisible by 100.

It can be seen that by reducing the number of events entering the water tank, the problem of unbalanced flow velocity between upstream and downstream can indeed be alleviated, but the strength is not enough. Let's look at a piece of code again:

Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        for (int i = 0; ; i++) {
             emitter.onNext(i);
        }
    }
}).subscribeOn(Schedulers.io())
  .sample(2, TimeUnit.SECONDS)  //sample取样
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<Integer>() {
        @Override
        public void accept(Integer integer) throws Exception {
            Log.d(TAG, "" + integer);
        }
});

sampleAn operator is used here, as a brief introduction, this operator takes an event from the upstream and sends it to the downstream every specified time. Here we let it fetch an event to the downstream every 2 seconds, let's take a look at this The result of running it:

This time we can see that although the upstream is still sending out events, we only 每隔一定时间took one and put it in the water tank, but not all of them, so this time the memory only took up 5M.

You can go out and brag in the future: I used technical means to optimize a program, and finally made the memory usage change from more than 300M to less than 5M. 

In the final analysis, the above two methods are actually to reduce the number of events put into the water tank, so as to 数量win, but this method has one 缺点, that is 丢失了大部分的事件.

Then let's think about it from another angle. Since the speed of sending events upstream is too fast, then we should slow down the speed of sending events appropriately to 速度win from above. It sounds good, let's try:

Observable.create(new ObservableOnSubscribe<Integer>() {
     @Override
     public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
         for (int i = 0; ; i++) {
              emitter.onNext(i);
              Thread.sleep(2000);  //每次发送完事件延时2秒
         }
     }
}).subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<Integer>() {
       @Override
       public void accept(Integer integer) throws Exception {
          Log.d(TAG, "" + integer);
       }
});

This time we let the upstream send a delay of 2 seconds each time after sending an event, let's take a look at the running results:

Perfect! Everything is so perfect !

It can be seen that after we add a delay to the upstream, the bull that is in heat for a moment becomes like a lamb, so docile, so calm, and such a stable memory line, it is wonderful. And, 事件也没有丢失through 上游appropriate 延时, not only 减缓了events enter the water tank 速度, but also allow events to 下游be 充足的时间taken out of the water tank for processing. In this way, it will not cause a large number of events to flood into the water tank, and there will be no OOM.

So far, we have easily solved the problem of unbalanced upstream and downstream flow rates without relying on any other tools.

So let's summarize, there are two governance methods in this section:

  • One is to manage in terms of quantity and reduce the events sent into the water tank
  • The second is to control the speed and slow down the speed at which events are sent into the water tank

Everyone must not have forgotten that there was an example of Zip in the previous section, which also exploded our memory, so we can use what we have learned now to see if we can punish rape and eradicate evil. Let’s see first See the first method.

Let's first reduce the number of events entering the tank:

Observable<Integer> observable1 = Observable.create(new 
       ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        for (int i = 0; ; i++) {
             emitter.onNext(i);
        }
    }
}).subscribeOn(Schedulers.io())
  .sample(2, TimeUnit.SECONDS); //进行sample采样

Observable<String> observable2 = Observable.create(new 
       ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
       emitter.onNext("A");
    }
}).subscribeOn(Schedulers.io());

Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
    @Override
    public String apply(Integer integer, String s) throws Exception {
        return integer + s;
    }
}).observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<String>() {
       @Override
       public void accept(String s) throws Exception {
            Log.d(TAG, s);
       }
   }, new Consumer<Throwable>() {
       @Override
       public void accept(Throwable throwable) throws Exception {
            Log.w(TAG, throwable);
       }
   });

Let's try the running result:

It worked, let's try the second method again. This time let's slow down the speed:

Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
         for (int i = 0; ; i++) {
              emitter.onNext(i);
              Thread.sleep(2000);  //发送事件之后延时2秒
         }
    }
}).subscribeOn(Schedulers.io());

Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        emitter.onNext("A");
    }
}).subscribeOn(Schedulers.io());

Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
    @Override
    public String apply(Integer integer, String s) throws Exception {
        return integer + s;
    }
}).observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Consumer<String>() {
      @Override
      public void accept(String s) throws Exception {
           Log.d(TAG, s);
      }
 }, new Consumer<Throwable>() {
      @Override
      public void accept(Throwable throwable) throws Exception {
           Log.w(TAG, throwable);
      }
});

Let's take a look at the running results:

Sure enough, it succeeded, here only the events received by the downstream are printed, so there is only one. If you don’t understand this result, please consciously turn around and read the previous articles.

Through the study of this section, you should have a basic understanding of how to deal with the imbalance of upstream and downstream flow rates. You can also see that we have not used it, so we often analyze the problem carefully, find the cause of the problem, and start from the Flowablesource The most fundamental way is to solve it. FlowableWhen we talk about it later, you will find that there is nothing mysterious about it. The method it uses is basically the same as what we talked about in this section, but it does a little bit package.

Guess you like

Origin blog.csdn.net/m0_49508485/article/details/126994186