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.combine
或 Multi.collect
就像语法糖一样我。但我还是想问一下有什么区别吗?特别是性能方面的差异。
使用第一种方法,我正在调试一个错误,当 parameters
的大小超过 25 时,它开始出错,但小于 25 就可以了。因此,我怀疑第一种方法会导致非常高的 QPS 淹没外部服务。但是,我怀疑第二种方法是否有助于节流。
Uni组合(Uni.combine().all().uni(...))、transformToMultiAndConcatenate
和transformToMultiAndMerge
的并发模型不同
Uni组合同时运行所有通过的Unis。因此,如果您通过,假设 100 个 unis,则所有 100 个 unis 将同时执行。在您的情况下,这意味着发送 100 个请求。所以,是的,最好确保远程服务优雅地处理并发请求。组合函数以与组合单元相同的顺序接收结果列表。因此结合 UniA 和 UniB 将产生一个包含 ResponseForA、ResponseForB 的列表。
transformToMultiAndConcatenate
和 transformToUniAndConcatenate
的并发级别为 1。基本上,它分别从上游获取每个项目,调用您的服务,完成后切换到下一个项目。所以,这里的并发性不多。但是,它保证响应与来自上游的项目的顺序相同。因此,如果您将 [A, B, C] 作为上游项,则生成的 multi 将是 [对 A 的响应,对 B 的响应,对 C 的响应]。
transformToMultiAndMerge
和 transformToUniAndMerge
将同时执行几个请求。默认并发数为 128。因此,它将从上游消耗 128 个项目并调用您的远程服务。回复可能没有顺序。一旦收到一个响应,就会消耗另一个项目。
所以 [A, B, C] 可能会产生 [对 B 的响应,对 C 的响应,对 A 的响应]。
使用合并时,可以使用以下方式配置并发:multi.onItem().transformToMulti(mapper).merge(concurrency)
供参考:
- 将项目转换为 Uni 和 Multi(包含关于合并与连接的部分):https://smallrye.io/smallrye-mutiny/getting-started/transforming-items-async
- 串联和合并的区别:https://smallrye.io/smallrye-mutiny/guides/merge-concat
- 项目组合:https://smallrye.io/smallrye-mutiny/guides/combining-items
在我的 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.combine
或 Multi.collect
就像语法糖一样我。但我还是想问一下有什么区别吗?特别是性能方面的差异。
使用第一种方法,我正在调试一个错误,当 parameters
的大小超过 25 时,它开始出错,但小于 25 就可以了。因此,我怀疑第一种方法会导致非常高的 QPS 淹没外部服务。但是,我怀疑第二种方法是否有助于节流。
Uni组合(Uni.combine().all().uni(...))、transformToMultiAndConcatenate
和transformToMultiAndMerge
的并发模型不同
Uni组合同时运行所有通过的Unis。因此,如果您通过,假设 100 个 unis,则所有 100 个 unis 将同时执行。在您的情况下,这意味着发送 100 个请求。所以,是的,最好确保远程服务优雅地处理并发请求。组合函数以与组合单元相同的顺序接收结果列表。因此结合 UniA 和 UniB 将产生一个包含 ResponseForA、ResponseForB 的列表。
transformToMultiAndConcatenate
和 transformToUniAndConcatenate
的并发级别为 1。基本上,它分别从上游获取每个项目,调用您的服务,完成后切换到下一个项目。所以,这里的并发性不多。但是,它保证响应与来自上游的项目的顺序相同。因此,如果您将 [A, B, C] 作为上游项,则生成的 multi 将是 [对 A 的响应,对 B 的响应,对 C 的响应]。
transformToMultiAndMerge
和 transformToUniAndMerge
将同时执行几个请求。默认并发数为 128。因此,它将从上游消耗 128 个项目并调用您的远程服务。回复可能没有顺序。一旦收到一个响应,就会消耗另一个项目。
所以 [A, B, C] 可能会产生 [对 B 的响应,对 C 的响应,对 A 的响应]。
使用合并时,可以使用以下方式配置并发:multi.onItem().transformToMulti(mapper).merge(concurrency)
供参考:
- 将项目转换为 Uni 和 Multi(包含关于合并与连接的部分):https://smallrye.io/smallrye-mutiny/getting-started/transforming-items-async
- 串联和合并的区别:https://smallrye.io/smallrye-mutiny/guides/merge-concat
- 项目组合:https://smallrye.io/smallrye-mutiny/guides/combining-items