关于 RxJava2 backpressure的一些理解

RxJava2 中的背压

在RxJava2里,引入了Flowable这个类来处理backpressure,而Observable不包含backpressure处理。Flowable的三种Backpressure策略:

  • BackpressureStrategy.BUFFER
    onBackpressureBuffer是不丢弃数据的处理方式。把上游收到的全部缓存下来,等下游来请求再发给下游。相当于一个水库。但上游太快,水库(buffer)就会溢出。
  • BackpressureStrategy.DROP 与 BackpressureStrategy.LATEST
    Drop 和Latest 类似,都会丢弃数据,下游通过request请求产生令牌给上游,上游接收到多少令牌,就发送多少,当令牌为0的时候,上游开始丢弃数据。区别在于,drop直接丢弃数据不缓存数据。而latest缓存最新的一条数据,当上游收到令牌,就把缓存的上一条“最新”数据发送给下游。

例如 :

 Flowable<Integer> flowable =
                Flowable.create((FlowableOnSubscribe<Integer>) e -> {
                    for (int i = 0; i < Integer.MAX_VALUE; i++) {
                        Log.d(TAG, "onNext  : " + i);
                        e.onNext(i);
                        Thread.sleep(10);
                    }
                }, BackpressureStrategy.DROP).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());

Flowable以10毫秒一次派发数据,注意我们让Flowable和订阅者运行在不同的线程,这样才能看出生产与消费在不同效率下时的差异性,如果Flowable和订阅者在同一线程,背压是没什么意义的。假设订阅他们的方法都是:

Subscription mSubscription;
flowable.subscribe(new Subscriber<Integer>() {
            @Override
            public void onSubscribe(Subscription subscription) {
                mSubscription = subscription;
            }

            @Override
            public void onNext(Integer integer) {
                Log.d(TAG, "onNext: " + integer);
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {

            }
        });

我们在onSubscribe中保存了Subscription ,以后 方便我们可以在任何时候request 数据。我们添加一个按钮,以实现手动request数据 ,代码如下:

if(mSubscription != null) {
  mSubscription.request(64);
}

我们一开始request 64个数据,我们启动Flowable后,隔一段时间才点击request , log打印 0 ~ 63 :

D/SimpleExampleActivity: onNext: 0
D/SimpleExampleActivity: onNext: 1
D/SimpleExampleActivity: onNext: 2
...
D/SimpleExampleActivity: onNext: 63
D/SimpleExampleActivity: onNext: 64

隔一段时间第二次点击request , log打印 64~ 127 :

D/SimpleExampleActivity: onNext: 64
D/SimpleExampleActivity: onNext: 65
D/SimpleExampleActivity: onNext: 66
...
D/SimpleExampleActivity: onNext: 126
D/SimpleExampleActivity: onNext: 127

隔一段时间第三次点击request , log打印 1243~ 1306:

D/SimpleExampleActivity: onNext: 1243
D/SimpleExampleActivity: onNext: 1244
D/SimpleExampleActivity: onNext: 1245
...
D/SimpleExampleActivity: onNext: 1304
D/SimpleExampleActivity: onNext: 1305
D/SimpleExampleActivity: onNext: 1306

我们使用是BackpressureStrategy.DROP , 与就是 直接丢弃数据不缓存数据 。可是我们一开始隔了点时间再request时,还是打印从 0 ~ 127 , 这说明 Flowable 本身就会存储缓存 128 个数据,超过128个后执行我们的策略,也就是丢弃。所以 1243~ 1306 其实是我们在第二次点击后,重新缓存的128数据。如果我们换成 BackpressureStrategy.BUFFER , 那么不管你点击多少次,数据都是连续的,因为 BackpressureStrategy.BUFFER 策略会把数据一直放到内存中,直到发生OutOfMemoryError。
我们现在修改request 的数目 ,改成 每次 request 96 个 , 代码如下 :

if(mSubscription != null) {
  mSubscription.request(96);
}

第一次点击request , log打印 0 ~ 95 , 没什么问题

D/SimpleExampleActivity: onNext: 0
D/SimpleExampleActivity: onNext: 1
D/SimpleExampleActivity: onNext: 2
...
D/SimpleExampleActivity: onNext: 94
D/SimpleExampleActivity: onNext: 95

隔一段时间第二次点击request , log打印 96 ~ 127 , 188 ~ 251 :

D/SimpleExampleActivity: onNext: 96
D/SimpleExampleActivity: onNext: 97
D/SimpleExampleActivity: onNext: 98
...
D/SimpleExampleActivity: onNext: 126
D/SimpleExampleActivity: onNext: 127
D/SimpleExampleActivity: onNext: 188
D/SimpleExampleActivity: onNext: 189
...
D/SimpleExampleActivity: onNext: 250
D/SimpleExampleActivity: onNext: 251

隔一段时间第三次点击request , log打印 252 ~ 283 , 650 ~ 713:

D/SimpleExampleActivity: onNext: 252
D/SimpleExampleActivity: onNext: 253
...
D/SimpleExampleActivity: onNext: 282
D/SimpleExampleActivity: onNext: 283
D/SimpleExampleActivity: onNext: 650
D/SimpleExampleActivity: onNext: 651
...
D/SimpleExampleActivity: onNext: 712
D/SimpleExampleActivity: onNext: 713

我们可以看到第二次、第三次时打印的数据出现了中断的情况。我们知道Flowable 默认会缓存 127个数据,那么第一次点击之后应该剩下 128 - 96 = 32个 , 所以第二次首先打印 96 ~ 127 , 之后再打印 188 ~ 251 64个数据。第三次又打印了 252 ~ 283 32个数据。第二次打印中断之后打印的 64个数据 加上 第三次打印中断前打印的 32个,刚好是 96个数据,也就是打印中断的时间点的数据刚好是96个。
这个96就是Flowable 重新去拉取缓存的限制,这是在源码上设定的,就是说首先缓存了 128个数据之后,被消费了96个数据时才会重新缓存。所以在第二次时,从127后就打印了 188,因为这个188是在第一次点击之后就重新缓存了。

总结

Flowable 有三种Backpressure策略,分别是BackpressureStrategy.BUFFER、BackpressureStrategy.DROP 和 BackpressureStrategy.LATEST。默认会缓存 127个数据,被消费了96个数据后才会重新缓存。

参考

探索专为 Android 而设计的 RxJava 2
RxJava2 vs RxJava1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容