为什么rxjava2共享运算符不多播?

时间:2019-02-18 07:29:10

标签: rx-java rx-java2

多播是在我的所有订户都移到下一个发射之前都收到相同的发射时发生的。但是当我使用share命令时,我看不到多播。我有一个昂贵的手术,我只想做一次。让我们看一下这段代码:

var  ob1 = Observable.fromArray(1,2,3,4,5).map {
       println("expensive operation")
       it * 2
   }

    fun doMultiplyBy2(){
        ob1.flatMap { Observable.just(" 1st subscriber: $it;") }.subscribe{println(it)}

        ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }.subscribe{println(it)}

        ob1.share()
    }
}

这是实际输出:

    expensive operation
 1st subscriber: 2;
expensive operation
 1st subscriber: 4;
expensive operation
 1st subscriber: 6;
expensive operation
 1st subscriber: 8;
expensive operation
 1st subscriber: 10;
expensive operation
 2nd subscriber: 2;
expensive operation
 2nd subscriber: 4;
expensive operation
 2nd subscriber: 6;
expensive operation
 2nd subscriber: 8;
expensive operation
 2nd subscriber: 10;

但是为什么要在向所有用户发出信号之前重复昂贵的操作。对每个用户重复昂贵的操作?我正在使用共享,所以我希望输出是这样的:

    expensive operation
 1st subscriber: 2;
 2nd subscriber: 2;
expensive operation
 1st subscriber: 4;
 2nd subscriber: 4;
expensive operation
 1st subscriber: 6;
 2nd subscriber: 6;
expensive operation
 1st subscriber: 8;
 2nd subscriber: 8;
expensive operation
 1st subscriber: 10;
 2nd subscriber: 10;

有趣的是,我发现只有在执行以下操作时才会出现预期的输出:

var  ob1 = Observable.fromArray(1,2,3,4,5).map {
       println("expensive operation")
       it * 2
   }.publish()

    fun doMultiplyBy2(){
        ob1.flatMap { Observable.just(" 1st subscriber: $it;") }.subscribe{println(it)}

        ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }.subscribe{println(it)}

        ob1.connect()
    }
}

因此使其成为可连接的可观察对象,然后手动进行连接。为什么共享不起作用?

更新:我想非常清楚地说明问题所在:

share应该与publish()。refCount()相同,我也认为share会为我多播,但我看不到这样做。让我们看一下不使用共享,而是使用手动发布和连接:

 var  ob1 = Observable.fromArray(1,2,3,4,5).map {
       println("expensive operation")
       it * 2
   }.publish()

    fun doMultiplyBy2(){
        //ob1 = ob1.share()
        ob1.flatMap { Observable.just(" 1st subscriber: $it;") }.subscribe{println(it)}

        ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }.subscribe{println(it)}

        ob1.connect()
    }
}

此输出为:

expensive operation
 1st subscriber: 2;
 2nd subscriber: 2;
expensive operation
 1st subscriber: 4;
 2nd subscriber: 4;
expensive operation
 1st subscriber: 6;
 2nd subscriber: 6;
expensive operation
 1st subscriber: 8;
 2nd subscriber: 8;
expensive operation
 1st subscriber: 10;
 2nd subscriber: 10;

这正是我想要的。每次排放执行一次昂贵的操作。

不允许将其更改为使用共享:

var  ob1 = Observable.fromArray(1,2,3,4,5).map {
       println("expensive operation")
       it * 2
   }.publish().refCount()//or can use share()

    fun doMultiplyBy2(){
        ob1.flatMap { Observable.just(" 1st subscriber: $it;") }.subscribe{println(it)}

        ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }.subscribe{println(it)}
    }
}

产生以下输出:

    expensive operation
 1st subscriber: 2;
expensive operation
 1st subscriber: 4;
expensive operation
 1st subscriber: 6;
expensive operation
 1st subscriber: 8;
expensive operation
 1st subscriber: 10;
expensive operation
 2nd subscriber: 2;
expensive operation
 2nd subscriber: 4;
expensive operation
 2nd subscriber: 6;
expensive operation
 2nd subscriber: 8;
expensive operation
 2nd subscriber: 10;

如果publish()。refCount()不像普通的可观察对象那样多播,那么publish()。refCount()的目的是什么。什么意思或分享??

2 个答案:

答案 0 :(得分:2)

refCount()等效于refCount(1),这意味着可观察对象将在一个订阅者订阅时开始执行。

因此在以下示例中:

var ob1 = Observable.fromArray(1, 2, 3, 4, 5).map {
  println("expensive operation")
  it * 2
}
    .publish().refCount(1) // or .share() or .publish().refCount()

ob1.flatMap { Observable.just(" 1st subscriber: $it;") }
   .subscribe { println(it) }
ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }
   .subscribe { println(it) }

这是发生了什么

Observable has 0 subscribers  
Subscriber 1 subscribes  
Observable has 1 subscriber; refCount(1) condition is satisfied  
Observable EXECUTES EXPENSIVE OPERATION
Subscriber 1 executes onNext()  
Subscriber 1 executes onComplete() and unsubscribe  
Observable has 0 subscribers  
Subscriber 2 subscribes  
Observable has 1 subscriber; refCount(1) condition is satisfied  
Observable EXECUTES EXPENSIVE OPERATION
Subscriber 2 executes onNext()  
Subscriber 2 executes onComplete() and unsubscribe  
Observable has 0 subscribers  

如果要让Observable等待直到有2个订阅者,则必须增加到refCount(2)

因此在以下示例中:

var ob1 = Observable.fromArray(1, 2, 3, 4, 5).map {
  println("expensive operation")
  it * 2
}
    .publish().refCount(2) // <<<<< Increment to 2

ob1.flatMap { Observable.just(" 1st subscriber: $it;") }
   .subscribe { println(it) }
ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }
   .subscribe { println(it) }

这是发生了什么

Observable has 0 subscribers
Subscriber 1 subscribes
Observable has 1 subscriber
Subscriber 2 subscribes
Observable has 2 subscribers; refCount(2) condition is satisfied
Observable EXECUTES EXPENSIVE OPERATION
Subscriber 1 executes onNext()
Subscriber 2 executes onNext()
Subscriber 1 executes onComplete() and unsubscribe
Observable has 1 subscriber
Subscriber 2 executes onComplete() and unsubscribe
Observable has 0 subscribers

请注意,这次昂贵的操作仅执行一次。概括地说,如果您需要将昂贵的操作多播到N个下游可观察对象,请调用refCount(N)

答案 1 :(得分:1)

您知道share运算符是相同的publish().refCount()Refcount使connectable observer众所周知。因此您的代码是正确的。但是您缺少的是Thread。我想您可以理解我要解释的内容。如果没有让我知道!

像这样更改代码

val ob1 = Observable.fromArray(1,2,3,4,5).map {
    println("expensive operation")
    it * 2
}.subscribeOn(Schedulers.computation()).share() 
// Add subscribeOn operator to change emitting thread from MAIN to WORK

fun doMultiplyBy2() {
    ob1.flatMap { Observable.just(" 1st subscriber: $it;") }.subscribe{println(it)}

    ob1.flatMap { Observable.just(" 2nd subscriber: $it;") }.subscribe{println(it)}
}

doMultiplyBy2()

Thread.sleep(1000) // Waiting for ending to execute

输出

expensive operation
 1st subscriber: 2;
 2nd subscriber: 2;
expensive operation
 1st subscriber: 4;
 2nd subscriber: 4;
expensive operation
 1st subscriber: 6;
 2nd subscriber: 6;
expensive operation
 1st subscriber: 8;
 2nd subscriber: 8;
expensive operation
 1st subscriber: 10;
 2nd subscriber: 10;