可观察到重用操作员执行

时间:2016-07-05 06:18:05

标签: java rx-java reactive-programming kotlin

给出以下示例(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

在我的情况下,我在延迟和性能至关重要的情况下进行了非常昂贵的计算,我有一个热点可观察源和许多订阅者...

我们如何重用运营商执行?通常不同的映射操作?

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

问题解决了!