RxJava从并行计算中排序输出

时间:2015-10-13 12:17:45

标签: java multithreading reactive-programming rx-java

我有一个我想要在parallell中执行的任务列表,但我希望以与原始列表相同的顺序显示任务的结果。 换句话说,如果我有任务列表[A,B,C],我不希望在显示A结果之前显示B结果,但我也不想等到A-task完成后再启动B -任务。

另外,我希望尽快显示每个结果,换句话说,如果任务按顺序B完成,那么A,然后是C,我不希望在收到B结果时显示任何内容,然后当我收到A结果时,显示A结果后紧跟B结果,然后在收到结果时显示C结果。

当然,通过为每个任务创建一个Observable,将它们与merge相结合,并在计算线程池上进行订阅,然后编写一个为不按顺序接收的任何结果保存缓冲区的订阅服务器,这当然不是非常棘手。然而,Rx的经验法则往往是“#34;”已经是#34;的操作符,所以问题是"解决这个问题的RxJava方法是什么?"如果确实有这样的事情。

2 个答案:

答案 0 :(得分:1)

“没有相当的运营商”。虽然在1.0.15-SNAPSHOT版本中有一个实验concatEagar()运算符,但听起来它就像你正在寻找的那样。 Pull request for concatEager

repositories {
    maven { url 'https://oss.jfrog.org/libs-snapshot' }
}

dependencies {
    compile 'io.reactivex:rxjava:1.0.15-SNAPSHOT'
}

如果您希望推出自己的临时解决方案,直到concatEager()获得批准。你可以尝试这样的事情:

public Observable<Result> concatEager(final Observable<Result> taskA, final Observable<Result> taskB, final Observable<Result> taskC) {
    return Observable
            .create(subscriber -> {
                final Observable<Result> taskACached = taskA.cache();
                final Observable<Result> taskBCached = taskB.cache();
                final Observable<Result> taskCCached = taskC.cache();

                // Kick off all the tasks simultaneously.
                subscriber.add(
                        Observable
                                .merge(taskACached, taskBCached, taskCCached)
                                .subscribe(
                                        result -> {     // Throw away result
                                        },
                                        throwable -> {  // Ignore errors
                                        }
                                )
                );

                // Put the results in order.
                subscriber.add(
                        Observable
                                .concat(taskACached, taskBCached, taskCCached)
                                .subscribe(subscriber)
                );
            });
}

请注意,上述代码完全未经测试。可能有更好的方法来做到这一点,但这是首先想到的......

答案 1 :(得分:1)

对于此任务,您似乎需要concatEager,但有些可能使用1.0.15之前的工具来实现它,并且不需要创建&#34;观测。这是一个例子:

Observable<Long> source1 = Observable.interval(100, 100, TimeUnit.MILLISECONDS).take(10);
Observable<Long> source2 = Observable.interval(100, 100, TimeUnit.MILLISECONDS).take(20);
Observable<Long> source3 = Observable.interval(100, 100, TimeUnit.MILLISECONDS).take(15);

Observable<Observable<Long>> sources = Observable.just(source1, source2, source3);

sources.map(v -> {
    Observable<Long> c = v.cache();
    c.subscribe(); // to cache all
    return c;
})
.onBackpressureBuffer() // make sure all source started
.concatMap(v -> v)
.toBlocking()
.forEach(System.out::println);

缺点是它保留了整个序列持续时间的所有值。这可以通过一种特殊的主题来修复:UnicastSubject但是RxJava 1.x没有一个,并且可能没有得到一个&#34;正式&#34;。但是,您可以查看my blog posts中的一个,并为自己构建并具有以下代码:

//...
sources.map(v -> {
    UnicastSubject<Long> subject = UnicastSubject.create();
    v.subscribe(subject);
    return subject;
})
//...