RxJava 学习记 (四) — 1.x 背压

663 阅读3分钟
原文链接: blog.csdn.net

什么是背压(Backpressure)


(most from zhuanlan.zhihu.com/p/24473022?…)

背压是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。简而言之,背压是流速控制的一种策略。

若被观察者发送事件的速度太快,而观察者处理太慢,而且还没有做相应背压措施,可能抛出MissingBackpressureException
 

压力异常示例


Observable.interval(1, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.newThread())
                .subscribe(aLong -> {
                    Log.w("TAG","---->"+aLong);
                });

上面的interval操作符,在1毫秒产生一个事件,速率过快,订阅者”消费”事件来不及处理,就会出现异常。
 

自带背压处理的操作符


用自带背压处理的操作符来处理压力。

过滤策略

使用之前讲的”过滤操作符”,就可以有效缓解压力。

比如,使用throttleFirst来获取一段周期时间内的首个事件。

Observable.interval(1, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.newThread())
               .throttleFirst(200, TimeUnit.MILLISECONDS)
                .subscribe(aLong -> {
                    Log.w("TAG","---->"+aLong);
                });

 

缓存策略

缓存就是虽然被观察者发送事件速度很快,观察者处理不过来,但是可以选择先缓存一部分,然后慢慢读。

主要用到的是buffer操作符

Observable.interval(1, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.newThread())
               //这个操作符简单理解就是把100毫秒内的事件打包成list发送
                .buffer(100,TimeUnit.MILLISECONDS)
                .subscribe(aLong -> {
                    Log.w("TAG","---->"+aLong);
                });

 

按需拉取策略

就是需要”消费”多少个事件,自己告诉被观察者,最终实现了上游被观察者发送事件的速度的控制

主要使用request(long n)。这是一个protected方法

Observable.range(1, 10000)//生产从1到10000的数
  .observeOn(Schedulers.newThread())
  .subscribe(new Subscriber<Integer>() {

      @Override
      public void onStart() {
        super.onStart();
        //在onStart中通知被观察者先发送一个事件
        request(1);
      }

      @Override
      public void onCompleted() {

      }

      @Override
      public void onError(Throwable e) {

      }

      @Override
      public void onNext(Integer integer) {
        Log.w("TAG","---->"+ integer);
        request(1); //处理完毕之后,再通知被观察者发送下一个事件
      }
  });

上面的代码中,其实可以去掉request相关代码,因 range –> observeOn,这一段过程本身就是响应式拉取数据。

observeOn这个操作符内部有一个缓冲区RxRingBuffer,其在Android环境下长度是16,它会告诉range最多发送16个事件,充满缓冲区即可
 

让不支持背压的Observable“支持”背压


对于不支持背压的Observable除了使用上述两类生硬的操作符之外,还有更好的选择:onBackpressureBuffer、onBackpressureDrop。

onBackpressurebuffer:把Observable发送出来的事件做缓存,当request方法被调用的时候,
给下层流发送一个item(如果给这个缓存区设置了大小,那么超过了这个大小就会抛出异常)。

onBackpressureDrop:将Observable发送的事件抛弃掉,直到Subscriber再次调用request(n)方法的时候,
就发送给它这之后的n个事件。

使用了这两种操作符,可以让原本不支持背压的Observable“支持”背压了。

Observable.interval(1, TimeUnit.MILLISECONDS)
    .onBackpressureBuffer()
    .observeOn(Schedulers.newThread())
    .subscribe(aLong -> {
        Log.w("TAG--","---->"+aLong);
    });