【发布时间】:2018-12-14 06:35:01
【问题描述】:
我有两个端点:/parent 和 /child/{parentId}
两者都将返回列表
假设每次调用需要两秒钟。
因此,如果我打电话给/parent 并在列表中有 10 个父母,并且我想打电话给每个孩子并填充每个孩子,我总共需要 22 秒(/parent 需要 2 秒,/child/{parentId} 10 次,每次 2 秒)
在 Spring 和 Java 10 中,我可以使用 RestTemplate,结合 Future 进行异步调用。
在这个 sn-p 中,/slow-five 是对父级的调用,而/slow-six 是对子级的调用。
public List<Child> runSlow2() {
ExecutorService executor = Executors.newFixedThreadPool(5);
long start = System.currentTimeMillis();
RestTemplate restTemplate = new RestTemplate();
var futures = new ArrayList<Future<List<Child>>>();
var result = new ArrayList<Child>();
System.out.println("Start took (ms) : " + (System.currentTimeMillis() - start));
var responseFive = restTemplate.exchange("http://localhost:8005/api/r/slow-five", HttpMethod.GET, null,
new ParameterizedTypeReference<ResponseWrapper<Parent>>() {
});
for (var five : responseFive.getBody().getData()) {
// prepare future
var future = executor.submit(new Callable<List<Child>>() {
@Override
public List<Child> call() throws Exception {
var endpointChild = "http://localhost:8005/api/r/slow-six/" + five.getId();
var responseSix = restTemplate.exchange(endpointChild, HttpMethod.GET, null,
new ParameterizedTypeReference<ResponseWrapper<Child>>() {
});
return responseSix.getBody().getData();
}
});
futures.add(future);
}
for (var f : futures) {
try {
result.addAll(f.get());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Before return took (ms) : " + (System.currentTimeMillis() - start));
return result;
}
忽略 ResponseWrapper。它只是这样的包装类
public class ResponseWrapper<T> {
private List<T> data;
private String next;
}
代码运行良好,从 10 个父母那里收集所有孩子大约需要 3-4 秒。但我不认为它是有效的。
此外,Spring 5 有 WebClient 应该能够做这种事情。
但是,我找不到这种分层调用的任何示例。 WebClient 上的大多数示例仅涉及对单个端点的简单调用而没有依赖关系。
任何线索如何使用 WebClient 来实现相同的目标?异步调用多个/child并合并结果?
谢谢
【问题讨论】:
-
你试过给
ExecutorService更多线程吗?由于这是 i/o 工作,它应该受益于比可用处理器更多的线程,因为网络是瓶颈。
标签: java spring reactive-programming spring-webflux