Spring Webflux:FlatMap异步转换

时间:2019-07-29 09:45:38

标签: spring-webflux project-reactor

我已经阅读了Flatmap转换是异步的,在此示例中,我正在lambda定义内打印线程的名称。它正在打印与订阅源相同的线程。根据我的理解,它应该打印不同的线程名称-除了已预订源的线程名称以外,因为此转换必须在不同的线程中执行。

Flux.just(1, -2, 3, 4, -5, 6)
    .flatMap(element -> { 
        try { 
            Thread.sleep(1000);
        } 
        catch (InterruptedException e) {
            e.printStackTrace(); 
        } 

        System.out.println(Thread.currentThread().getName() + " element: " + element); 
        return Flux.just(element);
    })
    .subscribe()

3 个答案:

答案 0 :(得分:1)

它是异步的事实并不一定意味着它在 parallel 中运行,这似乎是您期望的。但是,您可以将Flux转换为ParallelFlux并指定并行调度程序:

Flux.just(1, -2, 3, 4, -5, 6)
        .parallel()
        .runOn(Schedulers.elastic())
        .flatMap(element
                -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) { // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()
                    + " element: " + element);

            return Flux.just(element);
        })
        .subscribe();
Thread.currentThread().join(); //Just a hack to keep the program alive.

另一方面,如果您不希望它并行运行,而只是在与主线程不同的线程上运行,则无需将其转换为并行的Flux-只需提供一个{ {1}}电话或类似电话。

答案 1 :(得分:1)

否,它不会输出其他线程名称。默认情况下,反应式在单个线程上运行-发生订阅。在这种情况下,预订发生在调用线程上,因此,所有元素都在该线程上发出并在该线程上进行进一步处理。

让我们首先尝试了解。flatMap的工作原理:

  1. 对于每个上游事件,您可以从中创建一个流。
  2. flatMap急切地订阅每个内部流(这就是为什么它们被触发的原因)。请注意,这里急切的意思是它立即订阅所有内部流,而无需等待其他内部流完成(与concatMap不同)。
  3. 在所有内部流发出事件时对其进行动态合并。

请注意,每个内部流毕竟是一个流。除非您告诉它使用不同的线程,否则每个线程都将在同一线程上发出(调用线程,您所发生的情况)。如果要并行处理它们,可以对它们每个进行.subscribeOn(Schedulers.elastic)(或schedulers.parallel())操作:

Flux.just(1, -2, 3, 4, -5, 6)
    .flatMap(
        element -> {
          //this will always print the same thread - the calling thread basically
          System.out.println(Thread.currentThread().getName() + " element: " + element);
          return Mono.just(element)
              .subscribeOn(Schedulers.parallel())
              .doOnNext(
                  a ->
                      System.out.println(
                          a + " emitted on thread: " + Thread.currentThread().getName()));
        })
    .subscribe();

flatMap不在乎元素进入哪个线程,什么线程退出-它所要做的就是订阅内部流并在事件出现时合并它们的事件。请记住,每个内部流都是一个“承诺”。它最终将完成(带有onComplete)信号,但是您不知道何时。 flatMap仍然不在乎。 concatMap但是,在订阅下一个流之前先等待流完成。这样便可以保持原始流的顺序。

在此阅读更多信息(我在flatMap上的文章):

https://medium.com/swlh/understanding-reactors-flatmap-operator-a6a7e62d3e95

答案 2 :(得分:0)

使用flatMap不会影响其执行的线程。您可以使用subscribeOn影响将在其上执行的线程:

        Flux.just(1, -2, 3, 4, -5, 6)
                .flatMap(element ->
                {
                    try { Thread.sleep(1000);
                    } catch (InterruptedException e) { // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() +
                            " element: " + element);
                    return Flux.just(element);
                })
                .subscribeOn(Schedulers.elastic())
                .subscribe();

根据您想要的行为,可以使用以下任何一种- Schedulers.elastic()Schedulers.single()Schedulers.parallel()Schedulers.immeadiate()