Concurrency RxJava—一个生产者,多个并发消费者,一次订阅

Concurrency RxJava—一个生产者,多个并发消费者,一次订阅,concurrency,rx-java,producer-consumer,Concurrency,Rx Java,Producer Consumer,我试图了解RxJava并发性的一些细节,但我不确定我的想法是否正确。我对SubscribeOn/ObserveOn的工作原理有很好的了解,但我正试图确定池调度程序的一些细节。为此,我希望实现一个1-N生产者-消费者链,尽可能简单地使用尽可能多的CPU 根据文档,Schedulers.computation()由与内核数量相同的线程池支持。然而,根据被动合同,操作员只能获得连续呼叫 因此,像这样的设置 Observable.range(1, 1000) // Whatever has to be

我试图了解RxJava并发性的一些细节,但我不确定我的想法是否正确。我对SubscribeOn/ObserveOn的工作原理有很好的了解,但我正试图确定池调度程序的一些细节。为此,我希望实现一个1-N生产者-消费者链,尽可能简单地使用尽可能多的CPU

根据文档,Schedulers.computation()由与内核数量相同的线程池支持。然而,根据被动合同,操作员只能获得连续呼叫

因此,像这样的设置

Observable.range(1, 1000) // Whatever has to be processed
            .observeOn(Schedulers.computation())
            .doOnNext(/* heavy computation */)
            .doOnCompleted(() -> System.out.println("COMPLETED"))
            .forEach(System.out::println);
尽管使用了线程池,但只会收到对doOnNext的并发调用。通过对
OperatorObserveOn.java
进行睡眠检查的实验似乎证实了这一点,因为每次
observeOn
调用都会获得一个工作者。此外,如果不是这样的话,应该有一个复杂的管理OnCompleted必须等待任何未决OnNext完成,我不认为存在

假设我在正确的轨道上(也就是说,只涉及一个线程,尽管你可以用observeOn跳过其中几个线程),那么正确的模式是什么?我可以找到相反情况的示例(将多个异步事件生成器同步到一个使用者中),但对于这种典型情况,这不是一个简单的示例

我猜flatMap也参与其中,可能是使用了限制并发订阅数量的beta版(1.x版)。也许可以像这样简单地使用window/flatMap

Observable
.range(1, 1000) // Whatever has to be processed
.window(1) // Emit one observable per item, for example 
.flatMap(/* Processing */, 4) // For 4-concurrent processing
.subscribe()
在这种方法中,我仍然缺少一种以Rx通用方式最大化CPU的简单方法(即,指定计算调度器,而不是flatMap的最大订阅数)。所以,也许…:

Observable
.range(1, 1000) // Whatever has to be processed
.window(1) // Emit one observable per item, for example 
.flatMap(v -> Observable.just(v)
                        .observeOn(Schedulers.computation())
                        .map(/* heavy parallel computation */))
.subscribe()

最后,在一些使用flatMap的示例中,我看到在
flatMap
之后有一个
toBlock()
调用,我不知道为什么需要调用它,因为flatMap不应该为下游执行序列化吗?(例如,在本例中:)

托马斯·尼尔德(Thomas Nield)的一篇好文章正是关于这个案例的

我个人在这种情况下所做的是,我只需在
flatMap
中订阅
Schedulers.io
,并使用最大并发调用参数

    Observable.range(1, 1000) // Whatever has to be processed
            .flatMap(v -> Observable.fromCallable(() -> { /* io calls */}) 
                    .subscribeOn(Schedulers.io()), Runtime.getRuntime().availableProcessors() + 1)
            .subscribe();
编辑 根据评论中的建议,最好使用
Schedulers.computation()
进行CPU受限的工作

    Observable.range(1, 1000) // Whatever has to be processed
            .flatMap(v -> Observable.fromCallable(() -> { /* intense calculation */}) 
                    .subscribeOn(Schedulers.computation()))
            .subscribe();

建议不要使用
Schedulers.io
执行CPU限制的任务。链接不错,这正是我需要的。我发现不需要调用
窗口
。。。也不太可能
toblock