RxJava - 一个生产者,单个订阅中的许多并发消费者

时间:2016-12-12 13:02:18

标签: concurrency rx-java producer-consumer

我正试图了解RxJava并发的一些细节,我不确定我的想法是否正确。我对SubscribeOn / ObserveOn如何工作有很好的理解,但我正在努力确定池调度程序的一些细节。为此,我正在寻求尽可能简单地实现与CPU一样多的消费者的1-N生产者 - 消费者链。

根据文档,Schedulers.computation()由与核心一样多的线程池支持。但是,根据Reactive合同,运营商只能获得顺序呼叫。

因此,像这样的设置

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的简单方法(即,指定计算Scheduler而不是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的一些示例中,我在toBlock()之后看到flatMap调用,我不确定为什么需要调用,因为flatMap不应该执行下游的序列化? (例如,在这个例子中:http://akarnokd.blogspot.com.es/2016/02/flatmap-part-1.html

1 个答案:

答案 0 :(得分:4)

托马斯·尼尔德(Thomas Nield)就这一案件发表了一篇很好的文章

RxJava - Maximizing Parallelization

在我遇到的情况下,我只是在Schedulers.io中使用flatMap订阅了最大并发呼叫参数。

    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();