RxJava2实战--第八章 RxJava的背压

1 背压

在RxJava中,会遇到被观察者发送消息太快以至于它的操作符或者订阅者不能及时处理相关的消息,这就是典型的背压(Back Pressure)场景。

BackPressure经常被翻译为背压,背压的字面意思比较晦涩,难以理解。它是指在异步场景下,被观察者发送事件速度远快于观察者处理的速度,从而导致下游的buffer溢出,这种现象叫做背压。

产生条件:

  1. 异步,被观察者和观察者处于不同的线程中。
  2. 被观察者发送消息的速度远远快于观察者处理的的数据

在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的背压的更多相关文章

  1. RxJava2实战--第二章 RxJava基础知识

    第二章 RxJava基础知识 1. Observable 1.1 RxJava的使用三步骤 创建Observable 创建Observer 使用subscribe()进行订阅 Observable.j ...

  2. Rxjava2实战--第四章 Rxjava的线程操作

    Rxjava2实战--第四章 Rxjava的线程操作 1 调度器(Scheduler)种类 1.1 RxJava线程介绍 默认情况下, 1.2 Scheduler Sheduler 作用 single ...

  3. RxJava2实战---第七章 合并操作符和连接操作符

    RxJava2实战---第七章 合并操作符和连接操作符 RxJava的合并操作符: startWith():在数据序列的开头增加一项数据. merge:将多个Observable合并为一个. merg ...

  4. RxJava2实战---第五章 变换操作符和过滤操作符

    RxJava2实战---第五章 变换操作符和过滤操作符 RxJava的变换操作符主要包括以下几种: map():对序列的每一项都用一个函数来变换Observable发射的数据序列. flatMap() ...

  5. RxJava2实战---第六章 条件操作符和布尔操作符

    RxJava2实战---第六章 条件操作符和布尔操作符 RxJava的条件操作符主要包括以下几个: amb():给定多个Observable,只让第一个发射数据的Obsrvable发射全部数据. de ...

  6. Rxjava2实战--第三章 创建操作符

    Rxjava2实战--第三章 创建操作符 Rxjava的创建操作符 操作符 用途 just() 将一个或多个对象转换成发射这个或者这些对象的一个Observable from() 将一个Iterabl ...

  7. Spring实战第八章学习笔记————使用Spring Web Flow

    Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...

  8. DirectX12 3D 游戏开发与实战第八章内容(下)

    DirectX12 3D 游戏开发与实战第八章内容(下) 8.9.材质的实现 下面是材质结构体的部分代码: // 简单的结构体来表示我们所演示的材料 struct Material { // 材质唯一 ...

  9. DirectX12 3D 游戏开发与实战第八章内容(上)

    8.光照 学习目标 对光照和材质的交互有基本的了解 了解局部光照和全局光照的区别 探究如何用数学来描述位于物体表面上某一点的"朝向",以此来确定入射光照射到表面的角度 学习如何正确 ...

随机推荐

  1. Nginx中虚拟主机配置

    一.Nginx中虚拟主机配置 1.基于域名的虚拟主机配置 1.修改宿主机的hosts文件(系统盘/windows/system32/driver/etc/HOSTS) linux : vim /etc ...

  2. C# NET 微信临时素材上传

    最近在做这个,一开始也是不明白为什么给个URL带着两个参数就直接上传了,网上看了很多都是PHP,但是PHP没看过是不会 的 所以就一直在找网上什么Demo之类的讲解,最后还是不错找到了一个比较好理解的 ...

  3. hexo主题hexo-theme-yilia文章太长,截断按钮文字的实现

    文章太长,截断按钮文字不是通过配置文件_config.yml实现的,而是在文章内容里实现,在你想截断的文章位置加上 <!-- more --> 就可以实现了! 参考博客:hexo-them ...

  4. 基于Hexo的个人博客搭建(下)

    5.服务器端测试 —5.1 clone到/var/www/html git clone /home/git/repos/myblog.git /var/www/html chown -R  git:g ...

  5. top命令参数详解

    简介 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. top显示系统当前的进程和其他状况,是一个动态显示过程,即可以通过用户按 ...

  6. HDU - 6435 Problem J. CSGO (曼哈顿距离变换)

    题目大意:有两类武器(主武器和副武器),每类有若干把,每把武器都有一个基础属性S,以及k个附加属性,让你选一把主武器M和一把副武器S,使得最大. 显然后面的和式是一个k维的曼哈顿距离,带绝对值符号不好 ...

  7. Suse环境下编译linux-2.6.24内核

    Suse环境下编译linux-2.6.24内核 1.下载linux-2.6.24内核源码: https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/ ...

  8. docker下安装运行mysql的过程以mysql5.7为例

    一.查找mysql资源 docker search mysql 其实这步顶多是看看有哪些mysql资源,除非你自己commit过一个特定的版本,否则直接执行下一步 二.安装mysql docker p ...

  9. 【leetcode】1275. Find Winner on a Tic Tac Toe Game

    题目如下: Tic-tac-toe is played by two players A and B on a 3 x 3 grid. Here are the rules of Tic-Tac-To ...

  10. ES大批量写入提高性能的策略

    1.用bulk批量写入 你如果要往es里面灌入数据的话,那么根据你的业务场景来,如果你的业务场景可以支持让你将一批数据聚合起来,一次性写入es,那么就尽量采用bulk的方式,每次批量写个几百条这样子. ...