RxJava flatMap不会交错结果

时间:2016-07-21 06:17:11

标签: java rx-java reactive-programming rx-android

根据ReactiveX文档:

enter image description here

  

请注意,FlatMap合并了这些Observable的发射,因此   他们可能交错。

我试了一下,似乎遇到了一个问题。

请注意,11, 12, 13 and 14一起在Scheduler.compute()个线程上一起运行。然后15 and 21在2秒后一起运行(预期,因为delayedIdentity(...)函数中指定的延迟)。但是,所有后续运行都在前一次运行后2秒发生(参见第7-10行;数据22, 23, 24 and 25)。我期望这最后4个交错,因为我使用了flatMap(...)。似乎在使用flatMap时,它会等待元素的结果,然后继续执行下一个元素的结果,从而阻止它进行交错。

我还使用了delayedEcho(...)替代delayedIdentity(...),它也产生了非交错结果。

给出以下代码:

public class Main {

    private static int i = 0;

    public static void main(String[] args) throws InterruptedException {
        System.out.println(MessageFormat.format("{0} {1} {2}", getLine(), Instant.now(), "Start"));

        Arrays.asList(11, 12, 13, 14, 15)
                .stream()
                .map(n -> Observable.just(n))
                .map(o -> o
                        .observeOn(Schedulers.computation())
                        .flatMap(Main::delayedIdentity)
                        .subscribe(Main::println))
                .collect(Collectors.toSet());

        Observable.just(21, 22, 23, 24, 25)
                .observeOn(Schedulers.computation())
                .flatMap(Main::delayedIdentity)
                .subscribe(Main::println);

        Thread.sleep(25 * 1000);
    }

    public static Observable<Integer> delayedIdentity(Integer n) {
        return Observable.create(s -> {
            try {
                Thread.sleep(2 * 1000);
                s.onNext(n);
                s.onCompleted();
            } catch (InterruptedException e) {
                s.onError(e);
            }
        });
    }

    public synchronized static void println(Object o) {
        System.out.println(MessageFormat.format("{0} {1} {2}", getLine(), Instant.now(), o));
    }

    public synchronized static int getLine() {
        return i++;
    }
}

给出以下控制台日志:

0 2016-07-21T06:05:36.908Z Start
1 2016-07-21T06:05:39.169Z 11
2 2016-07-21T06:05:39.169Z 14
3 2016-07-21T06:05:39.169Z 12
4 2016-07-21T06:05:39.170Z 13
5 2016-07-21T06:05:41.171Z 15
6 2016-07-21T06:05:41.172Z 21
7 2016-07-21T06:05:43.175Z 22
8 2016-07-21T06:05:45.176Z 23
9 2016-07-21T06:05:47.180Z 24
10 2016-07-21T06:05:49.182Z 25

Process finished with exit code 0

Echo alternative:

public static Observable<Integer> delayedEcho(Integer n) {
    return Observable.create(s -> {
        try {
            s.onNext(n);
            Thread.sleep(2 * 1000);
            s.onNext(n);
            s.onCompleted();
        } catch (InterruptedException e) {
            s.onError(e);
        }
    });
}

这导致了以下类似的结果:

0 2016-07-21T06:13:19.867Z Start
1 2016-07-21T06:13:20.073Z 11
2 2016-07-21T06:13:20.074Z 14
3 2016-07-21T06:13:20.074Z 13
4 2016-07-21T06:13:20.075Z 12
5 2016-07-21T06:13:22.078Z 11
6 2016-07-21T06:13:22.079Z 12
7 2016-07-21T06:13:22.079Z 13
8 2016-07-21T06:13:22.080Z 14
9 2016-07-21T06:13:22.081Z 15
10 2016-07-21T06:13:22.081Z 21
11 2016-07-21T06:13:24.087Z 15
12 2016-07-21T06:13:24.087Z 21
13 2016-07-21T06:13:24.087Z 22
14 2016-07-21T06:13:26.089Z 22
15 2016-07-21T06:13:26.089Z 23
16 2016-07-21T06:13:28.091Z 23
17 2016-07-21T06:13:28.092Z 24
18 2016-07-21T06:13:30.094Z 24
19 2016-07-21T06:13:30.095Z 25
20 2016-07-21T06:13:32.098Z 25

Process finished with exit code 0

我做错了什么?

1 个答案:

答案 0 :(得分:1)

为了确保你理解Schedulers.computation()调度程序 - 它不是一个线程,它主要是像线程池。如果1个线程忙,它将返回你的新线程。要检查它,只需放置类似

的内容
 System.out.println(MessageFormat.format("Thread id = {0}", Thread.currentThread().getId()));

delayedIdentity功能中。这个知识可能会更清楚。

我不是百分之百确定这里有什么令人困惑的,但我会尝试逐步解释结果。

Arrays.asList(11, 12, 13, 14, 15)
        .stream() 
        .map(n -> Observable.just(n)) 
        .map(o -> o 
                .observeOn(Schedulers.computation()) 
                .flatMap(Main::delayedIdentity) 
                .subscribe(Main::println)) 
        .collect(Collectors.toSet());

因此,当您运行该代码时,来自流的所有数据都将转换为5 Observables,然后,几乎在它们同时在延迟delayedIdentity之后开始仅发出一个项目。结果你几乎可以同时在控制台中看到11, 12, 13, 14, 15。它不应该保存订单,因为stream可以传递无序状态。

因此,因为你在第一个语句中使用非主线程,所以第二个语句将在第一个

之后立即开始
   Observable.just(21, 22, 23, 24, 25) 
            .observeOn(Schedulers.computation()) 
            .flatMap(Main::delayedIdentity) 
            .subscribe(Main::println);

所以简单地说21,在delayedIdentity几乎与11, 12, 13, 14, 15同时等待2秒,然后在控制台中打印所有这个数字。 22, 23, 24, 25 - 将在一段一秒的时间内相互打印。

请问我是否不清楚。