flatMap如何管理线程?

时间:2018-02-17 11:09:23

标签: java project-reactor

Flux.just("a", "b", "c")
        .log(null, Level.INFO,true) // line 18
        .flatMap(value -> Mono.just(value.toUpperCase())
                              .publishOn(Schedulers.elastic()), 2)
        .log(null, Level.INFO,true) // line 21
        .subscribe();

部分输出:

13:03:46 [main] INFO  - | request(2)    Flux.log(App.java:18)
13:03:46 [main] INFO  - | onNext(a)     Flux.log(App.java:18)
13:03:46 [main] INFO  - | onNext(b)     Flux.log(App.java:18)
13:03:46 [elastic-2] INFO  - onNext(A)  Flux.log(App.java:21)
13:03:46 [elastic-2] INFO  - | request(1)   Flux.log(App.java:18)
13:03:46 [main] INFO  - | onNext(c)     Flux.log(App.java:18)
13:03:46 [elastic-3] INFO  - onNext(B)  Flux.log(App.java:21)
13:03:46 [elastic-3] INFO  - | request(1)   Flux.log(App.java:18)
13:03:46 [elastic-2] INFO  - onNext(C)  Flux.log(App.java:21)
13:03:46 [elastic-2] INFO  - | request(1)   Flux.log(App.java:18)
13:03:46 [main] INFO  - | onComplete()  Flux.log(App.java:18)
13:03:46 [main] INFO  - onComplete()    Flux.log(App.java:21)

问题:

  1. 为什么flatMap要求main线程中有2个元素,然后从其他线程中请求更多元素?

  2. 为什么subscribe线程没有处理main

1 个答案:

答案 0 :(得分:1)

为什么2要求主线程?

第一个Subscription.request金额取决于您指定的并发级别2。由于您在主线程中调用.subscribe,因此将在该线程上准确调用第一个prefetch请求。

让我们来看看下一个架构:

.subscribe()[Thread main] - > FluxLog.source.subscribe()[Tread Main] - > FluxFlatMap.source.subscribe()[ThreadMain] - > FluxJust.subscriber.onSubscribe() - > FluxFlatMap.subscription.request(concurrency)[Thread Main]

接下来会发生什么?

然后,从那一点开始将是硬核:)。由于您的内部流将由FlatMapInner订阅,它将观察Scheduler.elastic上的所有信号(onNext,onError,onComplete)(因为您的.publishOn)。反过来,当内部流完成后,FlatMapInnner上的onComplete将通知主FlatMapMain,它是整个flatMap机制的驱动程序。 FlatMapInnerFlatMapMain之间的互动已超过FlatMapMain.innerComplete。因为,从FlatMapMain的角度来看,内部FlatMapInner扮演的角色是Queue,所有元素都将是drained。保持冷静,如果你不知道这里发生了什么,请不要惊慌。该方法的所有想法都是从内部流中排出数据并将其发送到下游,然后向上游请求新的数据部分。您应该记住的是innerCompleteFlatMapInner.onComplete调用并被移动到另一个调度程序,因此这意味着将从{{1}中指定的线程调用下一个Subscription.request }

因此,示意性地说明该过程如下:

Mono.just(value.toUpperCase()).publishOn(Schedulers.elastic()) - > FluxFlatMap.FlatMapMain.onNext [Thread Main] - > Publisher m = mapper(...) - > m.subscribe(new FluxFlatMap.FlatMapInner()) - > FluxFlatMap.FlatMapInner.onNext("a") [Thread Elastic N] - > LambdaSubscriber.onNext("c") [Thread Elastic N] - > FluxFlatMap.FlatMapInner.onComplete() [Thread Elastic N] - > FluxFlatMap.FlatMapMain.drainLoop() [Thread Elastic N] - > FluxFlatMap.FlatMapMain.drainLoop() [Thread Elastic N] { ... subscription.request(amountOfCompletedInners) - > .... FlatMap.FlatMapMain.onNext() [Thread Elastic N] - > ....

因此,您将看到main上的第一个请求(2),然后是弹性请求(1)(因为一个内部已经完成,因此FlatMap将从上游请求另一个1元素以满足并发的要求)。