简体   繁体   English

RxJava从并行计算中排序输出

[英]RxJava sorted output from parallell computation

I have a list of tasks I want to perform in parallell, but I want to display the result of the tasks in the same order as the original list. 我有一个我想要在parallell中执行的任务列表,但我想以与原始列表相同的顺序显示任务的结果。 In other words, if I have task list [A,B,C], I do not wish to show B-result before I have shown A-result, but nor do I want to wait until A-task is finished before starting B-task. 换句话说,如果我有任务列表[A,B,C],我不希望在显示A结果之前显示B结果,但我也不想等到A-task完成后再启动B -任务。

Additionally, I want to show each result as soon as possible, in other words, if the tasks finish in the order B, then A, then C, I do not want to show anything when I receive B-result, then show A-result immediately followed by B-result when I receive A-result, then show C-result whenever I receive it. 另外,我希望尽快显示每个结果,换句话说,如果任务按顺序B完成,那么A,然后C,我不想在收到B-result时显示任何内容,然后显示A-当我收到A结果时,结果会立即跟随B结果,然后在收到结果时显示C结果。

This is of course not terribly tricky to do by making an Observable for each task, combining them with merge, and subscribing on a computation thread pool, then writing a Subscriber which holds a buffer for any results received out of order. 当然,通过为每个任务创建一个Observable,将它们与merge相结合,并在计算线程池上进行预订,然后编写一个为不按顺序接收的任何结果保存缓冲区的订阅服务器,这当然不是非常棘手。 However, the Rx rule of thumb tends to be "there's already an operator for that", so the question is "what is the proper RxJava way to solve this?" 然而,Rx经验法则倾向于“已经有了一个运算符”,所以问题是“什么是正确的RxJava解决方法?” if indeed there is such a thing. 如果确实有这样的事情。

"There's not quite an operator for that". “那里并没有那么多的经营者”。 Although, in the 1.0.15-SNAPSHOT build there is an experimental concatEagar() operator those sounds like it does what you're looking for. 虽然,在1.0.15-SNAPSHOT版本中有一个实验性的concatEagar()运算符,但听起来它就像你正在寻找的那样。 Pull request for concatEager 请求concatEager的请求

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

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

If you want to roll your own temporary solution until concatEager() gets the nod of approval. 如果你想推出自己的临时解决方案,直到concatEager()得到批准的点头。 You could try something like this: 你可以尝试这样的事情:

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

Note that the above code is totally untested. 请注意,上面的代码完全未经测试。 There are probably better ways to do this but this is what first came to mind... 可能有更好的方法来做到这一点,但这是首先想到的......

It seems you need concatEager for this task but it is somewhat possible to achieve it with pre 1.0.15 tools and no need for "creating" Observables. 看来你需要concatEager来完成这个任务,但是有些可能用1.0.15之前的工具实现它,而不需要“创建”Observables。 Here is an example for that: 这是一个例子:

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

The drawback is that it retains all values for the whole duration of the sequence. 缺点是它保留了整个序列持续时间的所有值。 This can be fixed with a special kind of Subject: UnicastSubject but RxJava 1.x doesn't have one and may not get one "officially". 这可以通过一种特殊的主题来修复: UnicastSubject但是RxJava 1.x没有一个,可能没有“正式”。 You can, however, look at one of my blog posts and build if for yourself and have the following code: 但是,您可以查看我的一篇博文,并为自己构建并拥有以下代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM