Uni.combine().all().unis() v.s。 Multi..onItem().transformTo Multi 和 Concatenate().collect()

Uni.combine().all().unis() v.s. Multi..onItem().transformToMultiAndConcatenate().collect()

在我的 Quarkus 服务中,我需要从外部服务获取结果列表,我发现有两种方法可以实现相同的目标:

基于Uni.combine().all()的第一种方法:

List<Uni<Result>> results = new ArrayList();
for (Parameter p : parameters) {
  // callService returns Uni<Result>
  results.add(callService(p));
}
// collect all the results
Uni<List<Result>> combined = Uni.combine().all().unis(results)...

基于Multi..onItem().transformToMultiAndConcatenate().collect()

的第二种方法
Multi.createFrom().iterable(parameters)
.onItem()
.transformToMultiAndConcatenate(p -> callService(p))
.collect().asList()

一开始我认为这两种方法之间没有任何真正的区别,因为 Uni 是惰性评估的,而 Uni.combineMulti.collect 就像语法糖一样我。但我还是想问一下有什么区别吗?特别是性能方面的差异。

使用第一种方法,我正在调试一个错误,当 parameters 的大小超过 25 时,它开始出错,但小于 25 就可以了。因此,我怀疑第一种方法会导致非常高的 QPS 淹没外部服务。但是,我怀疑第二种方法是否有助于节流。

Uni组合(Uni.combine().all().uni(...))、transformToMultiAndConcatenatetransformToMultiAndMerge的并发模型不同

Uni组合同时运行所有通过的Unis。因此,如果您通过,假设 100 个 unis,则所有 100 个 unis 将同时执行。在您的情况下,这意味着发送 100 个请求。所以,是的,最好确保远程服务优雅地处理并发请求。组合函数以与组合单元相同的顺序接收结果列表。因此结合 UniA 和 UniB 将产生一个包含 ResponseForA、ResponseForB 的列表。

transformToMultiAndConcatenatetransformToUniAndConcatenate 的并发级别为 1。基本上,它分别从上游获取每个项目,调用您的服务,完成后切换到下一个项目。所以,这里的并发性不多。但是,它保证响应与来自上游的项目的顺序相同。因此,如果您将 [A, B, C] 作为上游项,则生成的 multi 将是 [对 A 的响应,对 B 的响应,对 C 的响应]。

transformToMultiAndMergetransformToUniAndMerge 将同时执行几个请求。默认并发数为 128。因此,它将从上游消耗 128 个项目并调用您的远程服务。回复可能没有顺序。一旦收到一个响应,就会消耗另一个项目。 所以 [A, B, C] 可能会产生 [对 B 的响应,对 C 的响应,对 A 的响应]。

使用合并时,可以使用以下方式配置并发:multi.onItem().transformToMulti(mapper).merge(concurrency)

供参考: