关于Reactor信号的基本问题

时间:2018-02-17 10:06:53

标签: java project-reactor reactive-streams

我对以下代码的输出有一些疑问:

101

输出:

Flux.just("a", "b", "c", "d")
        .log(null, Level.INFO, true) // line: 18
        .flatMap(value ->
                Mono.just(value.toUpperCase()).publishOn(Schedulers.elastic()), 2)
        .log(null, Level.INFO, true) // line: 21
        .take(3)
        .log(null, Level.INFO, true) // line: 23
        .subscribe(x -> 
             System.out.println("Thread: " + Thread.currentThread().getName() +
                               " , " + x));

Thread.sleep(1000 * 1000);

问题:每个问题都与输出中的特定行有关(而不是代码中的一行)。我还将其答案添加到其中一些但我不确定我是否正确。

  1. 订阅时,订阅操作会询问1. 11:29:11 [main] INFO - | onSubscribe([Synchronous Fuseable] FluxArray.ArraySubscription) Flux.log(App.java:18) 2. 11:29:11 [main] INFO - onSubscribe(FluxFlatMap.FlatMapMain) Flux.log(App.java:21) 3. 11:29:11 [main] INFO - onSubscribe(FluxTake.TakeSubscriber) Flux.log(App.java:23) 4. 11:29:11 [main] INFO - request(unbounded) Flux.log(App.java:23) 5. 11:29:11 [main] INFO - request(unbounded) Flux.log(App.java:21) 6. 11:29:11 [main] INFO - | request(2) Flux.log(App.java:18) 7. 11:29:11 [main] INFO - | onNext(a) Flux.log(App.java:18) 8. 11:29:11 [main] INFO - | onNext(b) Flux.log(App.java:18) 9. 11:29:11 [elastic-2] INFO - onNext(A) Flux.log(App.java:21) 10. 11:29:11 [elastic-2] INFO - onNext(A) Flux.log(App.java:23) 11. Thread: elastic-2 , A 12. 11:29:11 [elastic-2] INFO - | request(1) Flux.log(App.java:18) 13. 11:29:11 [main] INFO - | onNext(c) Flux.log(App.java:18) 14. 11:29:11 [elastic-3] INFO - onNext(B) Flux.log(App.java:21) 15. 11:29:11 [elastic-3] INFO - onNext(B) Flux.log(App.java:23) 16. Thread: elastic-3 , B 17. 11:29:11 [elastic-3] INFO - | request(1) Flux.log(App.java:18) 18. 11:29:11 [elastic-3] INFO - | onNext(d) Flux.log(App.java:18) 19. 11:29:11 [elastic-3] INFO - | onComplete() Flux.log(App.java:18) 20. 11:29:11 [elastic-3] INFO - onNext(C) Flux.log(App.java:21) 21. 11:29:11 [elastic-3] INFO - onNext(C) Flux.log(App.java:23) 22. Thread: elastic-3 , C 23. 11:29:11 [elastic-3] INFO - cancel() Flux.log(App.java:21) 24. 11:29:11 [elastic-3] INFO - onComplete() Flux.log(App.java:23) 25. 11:29:11 [elastic-3] INFO - | cancel() Flux.log(App.java:18) 个元素。那么为什么事件:unbounded正在进入管道而不是上升?我的回答:request(unbounded)金额的请求最多为unbounded,然后take再次向下发送。

  2. take发送flatMap信号。为什么不cancel发送它?

  3. 最后一个问题:输出中有多个终端信号。这不是反应流规范的推论吗?

1 个答案:

答案 0 :(得分:1)

在这种情况下,只会产生一个终端信号。

Flux.just("a", "b", "c", "d")
            .log(null, Level.INFO, true) // line: 18
            .flatMap(value ->
                    Mono.just(value.toUpperCase()).publishOn(Schedulers.elastic()), 2)
            .log(null, Level.INFO, true) // line: 21
            .take(3)
            .log(null, Level.INFO, true) // line: 23
            .subscribe(x ->
                    System.out.println("Thread: " + Thread.currentThread().getName() +
 " , " + x), t -> {}, () -> System.out.println("Completed ""Only Once"));

这里棘手的部分是每个Reactor 3运营商都有自己的生命,并且它们都按照相同的规则运行 - 发出onComplete以通知下游运营商不再有数据。

由于您拥有.log()运算符和三个不同点,因此您将观察到来自onComplete.just.flatMap的三个独立.take(3)信号。

首先,您会看到onComplete中的.just,因为.flatMap的默认行为是正常的,让我们首先尝试请求concurrency元素,然后让我们看看它是怎么回事,因为.just可能产生(在你的情况下)只有4个元素,在2(这是你的例子中的并发级别)请求它将发出2 onNext以及两request(1)后,您会看到onComplete。反过来,发出onComplete.flatMap知道当4个扁平流发出.onComplete信号时,它将被允许向下游发出自己的onComplete。 反过来,下游是.take(3)运算符,也是在前三个元素发出自己的onComplete信号之后,而不等待上游onComplete。由于在.log之后有.take运算符,因此也会记录此信号。 最后,在您的流程中,您有3个独立的日志运算符,它们将记录来自3个独立运算符的3个独立onComplete,但尽管如此,最终终端.subscribe将只收到一个onComplete从第一个操作员到流程。

关于.take行为的小更新

.take的核心思想是在满足剩余计数之前采用元素。由于上游可能产生超过要求的数量,我们需要有一种机制来防止发送更多数据。 Reactive-Streams规范为我们提供的机制之一是Subscription上的协作。订阅有两个主要方法 - request - 显示需求和cancel - 表明即使请求的需求不满足,也不再需要数据。 如果是.take运算符,initial demandLong.MAX_VALUE,则视为无限制需求。因此,停止使用可能不确定的数据流的唯一方法是cancel订阅,或者换句话说取消订阅

希望它可以帮助你:)