Rxjava2.0学习笔记(三)

吐槽

最近早上起来好困啊啊啊,特别特别想睡觉,早上起来还是看书吧,实在不行看看慕课网上免费的学习视频,感觉上面还是蛮不错的。
参考的大佬博客的链接

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);
    }

总结

看到别人大佬写的博客,就感觉人家想问题是往实质去思考,其实很多事情的本质不难,就是一大堆事情要分析,但仔细想想,复杂的事情就是由很多简单的事情组成,自己以后处理问题时候也要这样思考。

猜你喜欢

转载自blog.csdn.net/sakurakider/article/details/81558538