我正试图了解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)
答案 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();