(五)https://www.jianshu.com/p/0f2d6c2387c9
1、使用zip操作符,发送事件内容未组合前存放于“水缸”。
2、当上下游工作在同一个线程
中时, 这时候是一个同步
的订阅关系, 也就是说上游
每发送一个事件必须
等到下游
接收处理完了以后才能接着发送下一个事件。
当上下游工作在不同的线程
中时, 这时候是一个异步
的订阅关系, 这个时候上游
发送数据不需要
等待下游
接收。这时候就需要“水缸”了--上游把事件发送到水缸里去, 下游从水缸里取出事件来处理。若上游发事件的速度太快, 下游取事件的速度太慢, 水缸就会迅速装满, 然后溢出来, 最后就OOM了.
(六)https://www.jianshu.com/p/e4c6d7989356
解决(五)中上下游流速不均衡导致OOM的问题,解决方法有几种:
1、fliter操作符,筛出满足要求的事件放到“水缸”中
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; //能被10整除的数可以通过
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "" + integer);
}
});
2、sample操作符,取样,每隔指定的时间就从上游中取出一个事件发送给下游.
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);
}
});
以上两种方法,减少了放进“水缸”的数量,缺点是:丢失了大部分事件。
其实,解决我们的问题,除了可以从数量上进行治理, 减少发送进水缸里的事件,还可以从速度上进行治理, 减缓事件发送进水缸的速度。
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);
}
});
(七)https://www.jianshu.com/p/9b1304435564
1、背压
rxjava2.x的Observable是不存在背压的概念的。背压,Backpressure,是下游控制上游流速的一种手段。在rxjava1.x的时代,上游会给下游set一个producer,下游通过producer向上游请求n个数据,这样上游就有记录下游请求了多少个数据,然后下游请求多少个上游就给多少个,这就是背压。在rxjava2.x时代,上述的背压逻辑全部挪到Flowable里了,所以说Flowable支持背压。而2.x时代的Observable是没有背压的概念的。官方文档建议,大数据流用Flowable,小数据流用Observable。
2、Flowable
使用Observable时上游和下游分别是Observable
和Observer。使用Flowable时,
上游变成了Flowable
, 下游变成了Subscriber,订阅依然是通过subscribe。
Flowable<Integer> upstream = Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
Log.d(TAG, "emit 1");
emitter.onNext(1);
Log.d(TAG, "emit 2");
emitter.onNext(2);
Log.d(TAG, "emit 3");
emitter.onNext(3);
Log.d(TAG, "emit complete");
emitter.onComplete();
}
}, BackpressureStrategy.ERROR); //增加了一个参数
Subscriber<Integer> downstream = new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "onSubscribe");
s.request(Long.MAX_VALUE); //注意这句代码
}
@Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
@Override
public void onError(Throwable t) {
Log.w(TAG, "onError: ", t);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
};
upstream.subscribe(downstream);
注意: (1)创建Flowable时多了一个参数
BackpressureStrategy.ERROR,这是一种背压策略,当出现上下游流速不均衡的时候会抛出一个异常 MissingBackpressureException
(2)下游的onSubscribe
方法中传给我们的不再是Disposable
了, 而是Subscription。
调用Subscription.cancel()
也可以切断水管,达到和 Disposable.dispose() 一样的效果。不过这里的Subscription
增加了一个void request(long n)
方法。
这里,Flowable采用了一种响应式拉取方式(背压)来解决流速不均衡问题。下游请求可以处理多少个,上游就给多少个,下游处理完了再请求,上游再给。
在同步,上下游处于相同线程中时,下游需要执行方法 Subscription.request(n),不然上游认为下游没有处理事件的能力,就会抛出异常MissingBackpressureException。异步时,上下游处于不同线程,下游未执行Subscription.request(n)是有可能不抛出异常MissingBackpressureException的,原因在于,Flowable默认有一个大小为128的“水缸”。当上下游工作在不同的线程中时, 上游就会先把事件发送到这个水缸中, 因此, 下游虽然没有调用request, 但是上游在水缸中保存着这些事件, 只有当下游调用request时, 才从水缸里取出事件发给下游.所以当上游事件数量少于128时是不会抛出异常的,即使超过了128,若下游发生请求了使“水缸”的数量一直处于128也是不会抛出异常的。