在flatMap上使用reduce时,Reactor Flux用户流停止

时间:2018-11-26 09:08:06

标签: java spring-webflux project-reactor

我想更改单个订户的代码。现在我有

auctionFlux.window(Duration.ofSeconds(120), Duration.ofSeconds(120)).subscribe(
        s -> s.groupBy(Auction::getItem).subscribe( longAuctionGroupedFlux -> longAuctionGroupedFlux.reduce(new ItemDumpStats(), this::calculateStats )
));

此代码正常工作,reduce方法非常简单。我尝试更改单个订户的代码

    auctionFlux.window(Duration.ofSeconds(120), Duration.ofSeconds(120))
        .flatMap(window -> window.groupBy(Auction::getItem))
        .flatMap(longAuctionGroupedFlux -> longAuctionGroupedFlux.reduce(new ItemDumpStats(), this::calculateStats))
        .subscribe(itemDumpStatsMono -> log.info(itemDumpStatsMono.toString()));

这是我的代码,该代码不起作用。没有错误,没有结果。调试后,我发现减少流时代码被卡在第二个flatMap上。我认为问题在于flatMap合并,卡在Mono解析上。现在有人如何解决此问题并仅使用单个订户?

如何复制,您可以使用其他类或创建一个类。小尺寸正在工作,大尺寸正在消亡

List<Auction> auctionList = new ArrayList<>();
for (int i = 0;i<100000;i++){
    Auction a = new Auction((long) i, "test");
    a.setItem((long) (i%50));
    auctionList.add(a);
}

Flux.fromIterable(auctionList).groupBy(Auction::getId).flatMap(longAuctionGroupedFlux ->
        longAuctionGroupedFlux.reduce(new ItemDumpStats(), (itemDumpStats, auction) -> itemDumpStats)).collectList().subscribe(itemDumpStats -> System.out.println(itemDumpStats.toString()));

这种方法是立竿见影的,但我使用了3个订阅者

Flux.fromIterable(auctionList)
        .groupBy(Auction::getId)
        .subscribe(
                auctionIdAuctionGroupedFlux -> auctionIdAuctionGroupedFlux.reduce(new ItemDumpStats(), (itemDumpStats, auction) -> itemDumpStats).subscribe(itemDumpStats -> System.out.println(itemDumpStats.toString()
                )
        ));

2 个答案:

答案 0 :(得分:1)

我认为您描述的行为与groupByflatMap链接之间的交互有关。 查看groupBy文档。它指出:

  

需要使组耗尽并向下游消耗,以便groupBy正常工作。值得注意的是,当标准产生大量组时,如果组没有在下游适当使用,则可能导致挂起(例如,由于maxConcurrency参数设置得太低的flatMap)。

默认情况下,maxConcurrency (flatMap)设置为256(我检查了3.2.2的源代码)。所以, 选择超过256个组可能导致执行挂起(尤其是当所有执行发生在同一线程上时)。

以下代码有助于理解将操作员groupBy和flatMap链接在一起时发生的情况:

@Test
public void groupAndFlatmapTest() {
    val groupCount = 257;
    val groupSize = 513;
    val list = rangeClosed(1, groupSize * groupCount).boxed().collect(Collectors.toList());
    val source = Flux.fromIterable(list)
            .groupBy(i -> i % groupCount)
            .flatMap(Flux::collectList);
    StepVerifier.create(source).expectNextCount(groupCount).expectComplete().verify();
}

该代码的执行挂起。将groupCount更改为256或更小会使测试通过(对于groupSize的每个值)。

因此,关于您的原始问题,很有可能正在使用键选择器Auction::getItem创建大量组。

答案 1 :(得分:0)

添加了parallel已解决的问题,但我正在寻找答案,为什么可以大大降低缓慢的flatMap。