Java 为什么反应堆是';s Mono.fromCompletionStage比普通的CompletableFuture慢?

Java 为什么反应堆是';s Mono.fromCompletionStage比普通的CompletableFuture慢?,java,project-reactor,completable-future,Java,Project Reactor,Completable Future,我有一段简单的代码,可以在后台“处理”数据,在每个n个项目之后,记录在最后n个项目上花费的总时间: 类BackgroundWorker实现自动关闭{ 私有最终执行器服务线程=Executors.newSingleThreadExecutor(); 私人最终报告; 已处理的私有int; 私有本地时间开始; BackgroundWorker(int reportEvery){ this.reportEvery=reportEvery; } 可完成的未来流程(int项){ var future=新的C

我有一段简单的代码,可以在后台“处理”数据,在每个
n个
项目之后,记录在最后
n个
项目上花费的总时间:

类BackgroundWorker实现自动关闭{
私有最终执行器服务线程=Executors.newSingleThreadExecutor();
私人最终报告;
已处理的私有int;
私有本地时间开始;
BackgroundWorker(int reportEvery){
this.reportEvery=reportEvery;
}
可完成的未来流程(int项){
var future=新的CompletableFuture();
线程。提交(()->{
试一试{
如果(已处理==0){
begin=LocalTime.now();
}
如果(++processed==reportEvery){
System.out.format(“在%dms%n中处理了%d个项目”,
已处理,ChronoUnit.MILLIS.between(begin,LocalTime.now());
已处理=0;
}
未来。完成(真实);
}捕获(例外情况除外){
future.complete(假);
}
});
回归未来;
}
@凌驾
公众假期结束(){
thread.shutdownNow();
}
}
然后我有一个
Flux
,它将数据输入
BackgroundWorker
,计算成功完成的
CompletableFuture
s:

Flux number=Flux.fromStream(IntStream.range(0,100000).boxed());
try(var worker=newbackgroundworker(10000)){
int successCount=数字
.map(工作进程::进程)
.map(未来->未来,然后应用(成功->成功?1:0))
.减少(
CompletableFuture.completedFuture(0),
(acc,curr)->acc.thenCombine(curr,Integer::sum))
.block()
.join();
System.out.println(“完成;成功:+successCount”);
}
和同一段代码,但现在改用
Mono.fromCompletionStage

int successCount=数字
.map(工作进程::进程)
.map(Mono::fromCompletionStage)
.map(mono->mono.map(成功->成功?1:0))
.减少(
Mono.just(0),
(acc,curr)->acc.zipWith(curr,Integer::sum))
.block()
.block();
第一个使用futures的将打印以下内容:

Processed 10000 items in 48ms
Processed 10000 items in 17ms
Processed 10000 items in 10ms
Processed 10000 items in 8ms
Processed 10000 items in 9ms
Processed 10000 items in 5ms
Processed 10000 items in 5ms
Processed 10000 items in 4ms
Processed 10000 items in 3ms
Processed 10000 items in 4ms
Done; success: 100000
但是使用
Mono.fromCompletionStage
的版本会打印:

Processed 10000 items in 138ms
Processed 10000 items in 253ms
Processed 10000 items in 327ms
Processed 10000 items in 477ms
Processed 10000 items in 315ms
Processed 10000 items in 379ms
Processed 10000 items in 448ms
Processed 10000 items in 509ms
Processed 10000 items in 595ms
Processed 10000 items in 668ms
Done; success: 100000

为什么使用
Mono
而不是
CompletableFuture
会严重降低性能?

似乎是
Mono
s的压缩占用了最多的时间,并以某种方式影响了执行。可能是因为这样的压缩每次都会创建一个新的MonoZip实例

但在这一点上,您不必使用缩减和压缩。更惯用的方法是
flatMap
monos,获得一个
Flux
,在不创建中间垃圾的情况下减少流量

此外,由于futures基本上是在创建时开始处理的,因此您可以做一个更简单的
concatMap
(开销更少,而且此时必须等待每个mono的完成并不重要,因为所有futures都已经在后台运行了):


您分析过代码吗?但是使用
CompletableFuture
折叠也会创建新的未来实例,对吗?所以我仍然很好奇为什么
MonoZip
实例会有这样的开销。这就是说,使用
flatMap
提高了性能,与使用futures的性能不同,但速度足够快,因此这确实回答了我的问题。
Flux<Integer> numbers = Flux.fromStream(IntStream.range(0, 100_000).boxed());
try (BackgroundWorker worker = new BackgroundWorker(10000)) {
    int successCount = numbers
            .map(worker::process)
            .concatMap(future -> Mono.fromCompletionStage(future))
            .map(success -> success ? 1 : 0)
            .reduce(0, Integer::sum)
            .block();

    System.out.println("Done; success: " + successCount);
}
.reduce(0, (acc, bool) -> bool ? acc + 1 : acc)