吐槽
最近早上起来好困啊啊啊,特别特别想睡觉,早上起来还是看书吧,实在不行看看慕课网上免费的学习视频,感觉上面还是蛮不错的。
参考的大佬博客的链接
Rxjava2.0里面的水缸
在上一篇里面讲的两个上游一起发数据的时候,如果两个上游线程一样的话,就会发现,第一关上游先发完,然后第二个线程才继续发送,当时我们解决的问题的方式就是开两个线程,就好了。
如果其中一个水管A发送事件特别快, 而另一个水管B 发送事件特别慢, 那就可能出现这种情况, 发得快的水管A 已经发送了1000个事件了, 而发的慢的水管B 才发一个出来, 组合了一个之后水管A 还剩999个事件, 这些事件需要继续等待水管B 发送事件出来组合, 那么这么多的事件是放在哪里的呢
放在水缸里面
水缸
水缸其实是zip操作符内部一个机制,内部实现的原理就是队列,如果开两个线程的上游的情况下,一个发的快,一个发的慢的话,就会有个水缸把发的快的上游东西先存起来
- zip给每个水管也就是被观察者准备了水缸
- 它将每根水管发出的事件保存起来, 等两个水缸都有事件了之后就分别从水缸中取出一个事件来组合, 当其中一个水缸是空的时候就处于等待的状态
- 水缸也有大小的,不是无限存储的
水缸容量测试的Demo
就两个上游,一个无限发数字,一个就发一个A字符。, 第一根水管用机器指令的执行速度来无限循环发送事件, 第二根水管随便发送点什么, 由于我们没有发送Complete事件, 因此第一根水管会一直发事件到它对应的水缸里去
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for(int i = 0;;i++){
e.onNext(i);
}
}
}).subscribeOn(Schedulers.io());
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("A");
}
}).subscribeOn(Schedulers.io());
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String s) throws Exception {
return integer+s;
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("233", s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.w("233",throwable);
}
});
结果
结果是内存又爆了,,,水缸的存储的能力还是有限的,那这件事该如何解决呢,要从源头控制这个,既然你发的快,我不让你发的快不就好了。
简单控制速度的Demo
就先简单的上游发,下游接收,一个线程里面
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for(int i = 0;;i++){
e.onNext(i);
}
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Thread.sleep(2000);
Log.d("233",""+integer);
}
});
每次让下游接收事件的时候,延迟2秒,上游和下游在一个线程里面
结果:很平静的完成了任务
原因:因为上下游在一个线程里面
现在一个上游,一个下游,不在一个线程里面
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for(int i = 0;;i++){
e.onNext(i);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Thread.sleep(2000);
Log.d("233",""+integer);
}
});
上游切换到了IO线程中去, 下游到主线程去接收
然后结果是,,,,又爆表了
原因 :同步和异步的关系
- 当上游和下游在线程时候,这个时候他们两是同步的关系,也就是上游发一个,下游就收一个,必须等下游处理完了,才能接着发下一个
- 当上游和下游不在同一个线程的时候,这个时候他们是的关系,现在上游发送数据的时候不用等下游接收,因为两个线程不能直接进行通信,所以现在就有了水缸这种东西,把上游发送的事件存到水缸里面,下游再将水缸的东西取出来,然后再给下游。
- 当上游发的速度太快了,下游又太慢了,中转站就爆了,然后就尴尬了
同步的
异步的
同步和异步的区别仅仅在于是否有水缸.
有水缸就有速度不均匀的情况
如何解决水缸速度不均匀的情况
就是上游发的太快就把水缸挤爆了,现在要让其不把水缸弄爆,就想办法控制上游的速度
想到的就是两种方法,减少数量,控制时间
减少数量的方法
1对数据进行筛选
就是10的倍数才发
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
return integer %10 ==0;
}
})
2按照时间进行筛选
就是隔一段时间才发
.sample(2, TimeUnit.SECONDS)
但是这个还是没有解决实际问题
这两种方法归根到底其实就是减少放进水缸的事件的数量, 是以数量取胜, 但是这个方法有个缺点, 就是丢失了大部分的事件.
适当减慢发送事件的速度
每次发的时候延迟一点时间
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
for(int i = 0;;i++){
e.onNext(i);
Thread.sleep(2000);
}
总结
看到别人大佬写的博客,就感觉人家想问题是往实质去思考,其实很多事情的本质不难,就是一大堆事情要分析,但仔细想想,复杂的事情就是由很多简单的事情组成,自己以后处理问题时候也要这样思考。