给出以下示例(kotlin代码)
val subject = PublishSubject.create<Int>()
val stream = subject.map {
println("mapping")
it * 2
}
stream.forEach { println("A: $it") }
stream.forEach { println("B: $it") }
subject.onNext(1)
subject.onCompleted()
输出
mapping
A: 2
mapping
B: 2
我想要实现的是,source observable被映射一次并且所有订阅者都获得了结果,但是没有为每个订阅者执行映射操作......
像这样mapping
A: 2
B: 2
在我的情况下,我在延迟和性能至关重要的情况下进行了非常昂贵的计算,我有一个热点可观察源和许多订阅者...
我们如何重用运营商执行?通常不同的映射操作?
答案 0 :(得分:2)
您可以使用cache
将source observable的结果缓存到任何将来的订阅者:
val stream = subject.map {
println("mapping")
it * 2
}.cache()
如果您希望对缓存事物的方式进行更微妙的控制,replay
值得研究。
如果您不想缓存源可观察源的每个项目但仅重新发布新项目,则可以publish
使用autoConnect
:
val stream = subject.map {
println("mapping")
it * 2
}.publish()
.autoConnect()
给出以下事件序列:
stream.forEach { println("A: $it") }
stream.forEach { println("B: $it") }
subject.onNext(1)
stream.forEach { println("C: $it") }
subject.onNext(2)
subject.onCompleted()
会打印:
mapping
A: 2
B: 2
mapping
A: 4
B: 4
C: 4
答案 1 :(得分:1)
我找到了解决方案。为了重用管道的执行,我们必须确保只有一个用户,并且该用户将管道末端的所有排放传播到所有用户的条目......听起来很像主题!
如果我们只订阅100次,我们将从可观察源头开始有100个管道,而在这种情况下,我们有一个管道,在它的最后分支到100个小管道......
fun <T> Observable<T>.hub(): Observable<T> {
val hub = PublishSubject.create<T>()
this.subscribe(hub)
return hub
}
现在我们可以做到这一点
val subject = PublishSubject.create<Int>()
val stream = subject.map {
println("mapping")
it * 2
}
val hub = stream.hub()
hub.subscribe { println("A: $it") }
hub.subscribe { println("B: $it") }
subject.onNext(1)
subject.onCompleted()
将提供此
mapping
A: 2
B: 2
问题解决了!