如何使用RxJava批量处理串行长进程?

时间:2015-03-09 09:02:27

标签: reactive-programming rx-java

我有一个很大的字符串列表需要针对远程API进行检查。

Observable.from(List<String> strings) // let's say the `strings` has > 5000 items
   .buffer(50) // splitting the strings into 50-sized chunks, it returns Observable<List<String>> (fast)
   .flatMap((strings) -> {
       // checkPhoneNumbers is a network call using Retrofit's RxJava (slow)
       return mSyncApi.checkPhoneNumbers(strings);
   })
   .reduce( ... ) // aggregate all checking results
   .subscribe( ... );

问题是buffer()似乎发出List<String>的速度太快,导致所有多个.checkPhoneNumbers()几乎在同一时间内被执行。 我想要实现的是将.checkPhoneNumbers()排入队列以更好地支持连接速度较慢的设备。

按照预定义的时间间隔限制发出的List<String>没有意义,因为对于具有快速连接的设备来说它将是一个缺点。 我已经在serialize()之后尝试了RxJava的flatMap(),但它似乎没有任何区别(虽然我不知道它是否正确使用serialize)。

任何替代方法都值得赞赏!谢谢。

1 个答案:

答案 0 :(得分:3)

正如@zsxwing建议的那样,如果您试图限制maxConcurrent内发生的并发,我认为flatMap重载是您正在寻找的。

例如:https://gist.github.com/benjchristensen/a0350776a595fd6e3810#file-parallelexecution-java-L78

private static void flatMapBufferedExampleAsync() {
    final AtomicInteger total = new AtomicInteger();
    Observable.range(0, 500000000)
            .doOnNext(i -> total.incrementAndGet())
            .buffer(100)
            .doOnNext(i -> System.out.println("emit " + i))
            .flatMap(i -> {
                return Observable.from(i).subscribeOn(Schedulers.computation()).map(item -> {
                    // simulate computational work
                        try {
                            Thread.sleep(10);
                        } catch (Exception e) {
                        }
                        return item + " processed " + Thread.currentThread();
                    });
            }, 2 /* limit concurrency to 2 */) // <--- note argument here
           .toBlocking().forEach(System.out::println);

    System.out.println("total emitted: " + total.get());
}