我有一个 Spring Boot 应用程序,我们必须对第 3 方 REST 服务进行一些 http 调用。我们可能需要拨打 1 个电话或数千个电话。
我正在使用 @Async Spring Boot 注释和 CompletableFuture,如下所示:
long start = System.nanoTime();
List<String> list = new ArrayList<>();
List<CompletableFuture<List<String>>> allFutures = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
allFutures.add(httpClient.getStringAsync("Hello"));
}
List<String> unwrappedFutures = allFutures.stream()
.map(CompletableFuture::join)
.flatMap(List::stream)
.collect(Collectors.toList());
list.addAll(unwrappedFutures);
long duration = (System.nanoTime() - start) / 1_000_000;
log.info("Done in {} msecs", duration);
此代码大约需要 2 分钟才能对 getStringAsync() 方法进行 1000k 次调用,该方法有 1 秒的延迟。
在我的笔记本电脑上(“Runtime.getRuntime().availableProcessors()”显示有 12 个核心)或在 EKS 集群(现在核心数似乎是 1 个)上处理所需的时间相同。
我想我必须配置 ThreadPoolTaskExecutor,以便可用的核心数量越多,处理所需的时间就越少。
但是,我不太确定如何确定核心、最大池大小和队列容量。
我想知道池大小是否必须等于列表中的项目数?也就是说,如果列表有 1000 个项目,这意味着我们必须对远程服务进行 1000 次调用,那么我们需要 1000 个线程吗?看起来很多。
添加我的发现:
如果我将
ThreadPoolTaskExecutor
核心和最大大小设置为 12(我的笔记本电脑上的核心数量),至少 Runtime.getRuntime().availableProcessors()
显示的是这样的,则平均 1.4 分钟内进行 1000K 次调用。
如果我将
ThreadPoolTaskExecutor
核心和最大大小设置为 100,则平均 10 秒内进行 1000K 次调用。
如果我将
ThreadPoolTaskExecutor
核心和最大大小设置为 1000,则平均 1.4 秒内进行 1000K 次调用。这听起来很吸引人。但是,我正在我的笔记本电脑上进行隔离测试,在真实场景中会有很多其他事件正在处理,所以我认为这并不理想。