RxJava2实战--第八章 RxJava的背压
RxJava2实战--第八章 RxJava的背压
1 背压
在RxJava中,会遇到被观察者发送消息太快以至于它的操作符或者订阅者不能及时处理相关的消息,这就是典型的背压(Back Pressure)场景。
BackPressure经常被翻译为背压,背压的字面意思比较晦涩,难以理解。它是指在异步场景下,被观察者发送事件速度远快于观察者处理的速度,从而导致下游的buffer溢出,这种现象叫做背压。
产生条件:
- 异步,被观察者和观察者处于不同的线程中。
- 被观察者发送消息的速度远远快于观察者处理的的数据
在RxJava2.x中,只有Flowable类型是支持背压的,并且Flowable很多操作符内部都使用了背压策略,从而避免过多的数据填满内部的队列。
解决背压问题的方法:
1.1 过滤限流
通过使用限流操作符将被观察者产生的大部分事件过滤并抛弃,以达到限流的目的,间接降低事件发射的速度,例如使用以下操作符:
- sample:在一段时间内,只处理最后一个数据。
- throttleFirst:在一段时间内,只处理第一个数据。
- debounce:发送一个数据,开始计时,到了规定时间,若没有再发送数据,则开始处理数据,反之重新开始计时。
1.2 打包缓存
在被观察者发射事件过快导致观察者来不及处理的情况下,可以使用缓存类操作符将其中一部分打包缓存起来,再一点一点的处理其中的事件。
- buffer:将多个事件打包放入一个List中,再一起发射。
- window:将多个事件打包放入一个Observable中,再一起发射。
1.3 使用背压操作符
通过一些操作符来转化成支持背压的Observable
2. RxJava2.x的背压策略
在RxJava2.x中,Observable不在支持背压,而是改用Flowable来专门支持背压。默认队列大小为128,并且要求所有的操作符强制支持背压。
Flowable一共有5中背压策略(BackpressureStategy中定义):MISSING,ERROR,BUFFER,DROP,LATEST
2.1 MISSING
通过Create方法创建Flowable没有指定背压策略,不会通过onNext发射的数据做缓存或丢弃处理,需要下游通过飞呀操作符(onBackpressureBuffer()/onBackpressureDrop()/onBackpressureLatest())指定背压策略。
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i <1000 ; i++) {
emitter.onNext(i);
}
}
},BackpressureStrategy.MISSING)
.onBackpressureBuffer()
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
上面的代码执行的是buffer的背压策略。
2.2 ERROR
如果放入Flowable的异步缓存池中的数据超限了,则会抛出MissingBackpressureException异常
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i < 129; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
在Android中运行以上代码,会立即引起App Crash,引起以下Exception:
W/System.err: io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
W/System.err: at io.reactivex.internal.operators.flowable.FlowableCreate$ErrorAsyncEmitter.onOverflow(FlowableCreate.java:438)
at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:406)
因为Flowable的默认队列是128,所以讲上述代码的129改成128,程序就可以正常运行了。
2.3 BUFFER
Flowable的异步缓存池同Observable的一样,没有固定大小,可以无限制添加数据,不会抛出MissingBackpressureException异常,但会导致OOM(Out of Memory).
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0;; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
上述代码不会导致崩溃,但会引起ANR。
2.4 DROR
如果Flowable的异步缓存池满了,则会丢掉将要放入缓存池中的数据。
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0;i<129; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.DROP)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
在Android中运行这段代码,不会引起Crash,但只会打印出0~127,第128则被丢弃,因为Flowable的内部队列已经满了。
2.5 LATEST
如果缓存池满了,会丢掉将要放入缓存池中的数据。这一点与DROP策略一样,不同的是,不管缓存池的状态如何,LATEST策略会将最后一条数据强行放入缓存池中。
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
for (int i = 0;i<1000; i++) {
emitter.onNext(i);
}
}
}, BackpressureStrategy.LATEST)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
执行结果:
0
1
...
127
516
519
521
523
526
528
530
...
734
737
740
743
745
748
999
3. 其他
Flowable不仅可以通过create创建时需要制定背压策略,还可以在通过其他创建操作符,例如just、fromArray等创建后通过背压操作符指定背压策略。例如,
onBackpressreBuffer()对应BackpressureStategy.BUFFER,
onBackpressreDrop()对应BackpressureStategy.DROP,
onBackpressreLatest()对应BackpressureStategy.LATEST.
示例:
Flowable.interval(1, TimeUnit.MILLISECONDS)
.onBackpressureBuffer()
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
System.out.println(aLong);
}
});
RxJava2实战--第八章 RxJava的背压的更多相关文章
- RxJava2实战--第二章 RxJava基础知识
第二章 RxJava基础知识 1. Observable 1.1 RxJava的使用三步骤 创建Observable 创建Observer 使用subscribe()进行订阅 Observable.j ...
- Rxjava2实战--第四章 Rxjava的线程操作
Rxjava2实战--第四章 Rxjava的线程操作 1 调度器(Scheduler)种类 1.1 RxJava线程介绍 默认情况下, 1.2 Scheduler Sheduler 作用 single ...
- RxJava2实战---第七章 合并操作符和连接操作符
RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...
- RxJava2实战---第五章 变换操作符和过滤操作符
RxJava2实战---第五章 变换操作符和过滤操作符 RxJava的变换操作符主要包括以下几种: map():对序列的每一项都用一个函数来变换Observable发射的数据序列. flatMap() ...
- RxJava2实战---第六章 条件操作符和布尔操作符
RxJava2实战---第六章 条件操作符和布尔操作符 RxJava的条件操作符主要包括以下几个: amb():给定多个Observable,只让第一个发射数据的Obsrvable发射全部数据. de ...
- Rxjava2实战--第三章 创建操作符
Rxjava2实战--第三章 创建操作符 Rxjava的创建操作符 操作符 用途 just() 将一个或多个对象转换成发射这个或者这些对象的一个Observable from() 将一个Iterabl ...
- Spring实战第八章学习笔记————使用Spring Web Flow
Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...
- DirectX12 3D 游戏开发与实战第八章内容(下)
DirectX12 3D 游戏开发与实战第八章内容(下) 8.9.材质的实现 下面是材质结构体的部分代码: // 简单的结构体来表示我们所演示的材料 struct Material { // 材质唯一 ...
- DirectX12 3D 游戏开发与实战第八章内容(上)
8.光照 学习目标 对光照和材质的交互有基本的了解 了解局部光照和全局光照的区别 探究如何用数学来描述位于物体表面上某一点的"朝向",以此来确定入射光照射到表面的角度 学习如何正确 ...
随机推荐
- 复习rem
在Web页面制作中,我们一般使用“px”来设置我们的文本,因为他比较稳定和精确.但是这种方法存在一个问题,当用户在浏览器中浏览我们制作的Web页面时,他改变了浏览器的字体大小(虽然一般人不会去改变浏览 ...
- dedecms织梦后台发布文章提示“标题不能为空”的解决办法
V5.7登录后台后,发布英文标题没问题,发布中文会提示“标题不能为空”. 原因:htmlspecialchars在php5.4默认为utf8编码,gbk编码字符串经 htmlspecialchars ...
- Hdu 6268 点分治 树上背包 bitset 优化
给你一颗大小为n(3000)的树,树上每个点有点权(100000),再给你一个数m(100000) i为1~m,问树中是否存在一个子图,使得权值为i. 每次solve到一个节点 用一个bitset维护 ...
- c++分布式服务框架teamtalk
这是蘑菇街开发的内部通讯软件,记录一下.可以参考学习 https://github.com/meili/TeamTalk
- MySQL BinLog Server 搭建实战
一.MySQL Binlog server 介绍 MySQL Binlog Server: 它使用 mysqlbinlog 命令以 daemon 进程的方式模拟一个 slave 的 IO 线程与主库连 ...
- mysqldump 使用--tab=path参数时提示mysqldump: Got error: 1290: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement when executing 'SELECT INTO OUTFILE'
报错: [root@zedu test]# mysqldump -h127.0.0.1 -uroot -p --single-transaction --add-drop-database --tab ...
- $'\r': command not found
在Linux下执行程序最省事的方式就是将系统的执行流程封装成一个shell脚本,上传到linux环境中后就可以直接执行了,但是今天在具体实施的时候出现了错误 $'\r': command not fo ...
- 自动生成SSM框架
使用idea 新创建项目 然后 新创建 java .resources 文件夹...... 图上是项目结构 java文件夹下的 文件夹 命名规范 com.nf147(组织名)+ oukele(作者) ...
- 题解 [ZJOI2008]树的统计Count
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u ...
- react-helloword
1.在webpack项目中使用react 创建webpack项目步骤见: 创建基本的webpack4.x项目 webpack-dev-server 和 html-webpack-plugin的 ...