RxJava:带有zip()的concatMap()卡住了

时间:2018-09-29 07:58:21

标签: kotlin rxjs rx-java rx-java2 rx-kotlin

我有一个虚拟网络数据源:

    fun networkDataSource(): Single<List<Int>> {
        return Single.just((0 until 100).toList())
                .delay(150, TimeUnit.MILLISECONDS)
    }

这里是无尽的观察。主要用途是它的计算应该是“受保护的”,因此它仅计算一次它的单个值(此处为1。)

    val endless = Observable
            .just(1)
            .observeOn(Schedulers.io())
            .delay(500, TimeUnit.MILLISECONDS)
            // Counts as heavy operation, do not calculate this here once again
            .doOnNext { println("=> E: Calculated once") }
            .cache()
            //.doOnNext { println("=> E: From cache") }
            .repeat()

主流只是发出值:

    val mainStream = Observable.range(0, 6)
            .doOnNext { println("=> M: Main stream $it") }

任务:

将这三个可观察对象压缩在一起,并优化网络使用率,以至于调用它的次数不会超过必要。 (一旦满足数据数量(在这种情况下为整数)。

方法:

    mainStream
            .concatMap {index ->
                Observables.zip(
                        Observable.just(index),
                        endless,
                        networkDataSource()
                                .toObservable()
                                .doOnNext { println("#> N: Network data fetch $index") }
                )
            }
            .doOnNext { println("=> After concatmap: ${it.first}") }
            .take(4)
            .doOnNext { println("=> After take: ${it.first}") }
            .subscribe(
                    { println("=> Last onnext") },
                    { it.printStackTrace() },
                    { synchronized(check) { check.notifyAll() } }
            )

完成锁定的线程-仅用于测试:

synchronized(check) {
    check.wait()
}
println("Ending")

以下是输出:

=> M: Main stream 0
=> M: Main stream 1
=> M: Main stream 2
=> M: Main stream 3
=> M: Main stream 4
=> M: Main stream 5
#> N: Network data fetch 0
=> E: Calculated once
=> After concatmap: 0
=> After take: 0
=> Last onnext
#> N: Network data fetch 1
=> After concatmap: 1
=> After take: 1
=> Last onnext

此输出,在第二次拍摄后卡住。 (不会在一分钟内进行)。我的问题是,为什么会这样?

作为旁注,如果我取消注释endless中可观察到的行:

.doOnNext { println("=> E: From cache") }

它将用该行填充控制台。为什么endless每次迭代都被调用这么多次?

flatMap()在这里不是解决方案,因为它没有考虑take(4)并继续完成所有网络呼叫。

那我怎样才能使concatMap()工作呢?

(我还添加了 RxJS 标记,因为这是一个反应性问题,绝对不是Kotlin的问题。如果RxJava库中存在这些功能,也欢迎使用JS解决方案。)

编辑。

我查看了代码,结果2的输出可能是由于prefetch参数造成的:

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
    return concatMap(mapper, 2);
}

但是我仍然不明白它是如何工作的。我只读过concatMap()flatmap(),但它等待每个结果。

1 个答案:

答案 0 :(得分:1)

从评论中:

在第一项之后,整个设置可能会在同一线程上运行,并且CONCAT()中的repeat将永远不会放弃该线程,从而阻止了其他任何运算符的进行。对我而言,重复endless是没有意义的,因为您将只使用其中一项,并且仅使用其中一项。