我想知道在Java 8 Completable future中实现扇出类型功能的最佳方法是什么。我最近重写了一个函数,它有一堆旧的Future实例,然后使用CompletableFuture调用get in循环,阻塞每个实例,使用更清晰的变体。但是我看到性能下降了2倍,所以我假设我使用新API的方式不太正确。代码看起来像这样:
if (!clinet.login()) {
throw new LoginException("There was a login error");
}
CompletableFuture<List<String>> smths = CompletableFuture
.supplyAsync(client::getSmth);
CompletableFuture<List<Data>> smths2 = smths.thenApply(client::getInformation)
.thenApplyAsync((list) -> list.stream().map(obj -> mapper.map(obj, Data.class)).collect(toList()));
List<CompletableFuture<Map<String, AnotherData>>> waitGroup = new ArrayList<>();
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getIvPercentileM12M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getIvPercentileM6M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getIvPercentile2M6M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getIvPercentile2M12M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getIvPercentile2M24M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getHvPercentileM6M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getHvPercentile2M6M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getHvPercentileM12M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getHvPercentile2M12M));
waitGroup.add(notablesFuture.thenComposeAsync(clientb::getHvPercentile2M24M));
CompletableFuture
.allOf(waitGroup.toArray(new CompletableFuture[waitGroup.size()]));
List<Data> data = smths2.join();
Map<String, Set<AnotherData>> volPercent = waitGroup.stream()
.map(CompletableFuture::join)
.flatMap((e) -> e.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue,
toSet())));
data.forEach((d) -> {
Set<AnotherData> asdasd = volPercent.get(d.getSymbol());
if (asdasd != null) {
d.add(asdasd);
}
});
return stocks;
client :: getInformation 是一个阻止网络调用返回List,所有 clientb。* 正在执行的操作如下:
return CompletableFuture.supplyAsync(() -> blockingNetworkCall(params, symbols)
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, value -> new Data(value.getValue(), TimePeriod.M1, TimePeriod.Y1))));
原始代码看起来像这样:
List<String> symbols = client.block().get();
Future<Map<String, Data>> smth = client.block2(symbols);
Future<Map<String, Double>> ivM6MResultsFuture = clientB.getIvdataM6M(symbols);
Future<Map<String, Double>> ivM12MResultsFuture = clientB.getIvdataM12M(symbols);
Future<Map<String, Double>> iv2M6MResultsFuture = clientB.getIvdata2M6M(symbols);
Future<Map<String, Double>> iv2M12MResultsFuture = clientB.getIvdata2M12M(symbols);
Future<Map<String, Double>> iv2M24MResultsFuture = clientB.getIvdata2M24M(symbols);
Future<Map<String, Double>> hvM6MResultsFuture = clientB.getHvdataM6M(symbols);
Future<Map<String, Double>> hvM12MResultsFuture = clientB.getHvdataM12M(symbols);
Future<Map<String, Double>> hv2M6MResultsFuture = clientB.getHvdata2M6M(symbols);
Future<Map<String, Double>> hv2M12MResultsFuture = clientB.getHvdata2M12M(symbols);
Future<Map<String, Double>> hv2M24MResultsFuture = clientB.getHvdata2M24M(symbols);
Map<String, Data> doughResults = smth.get();
Map<String, Double> ivM6MResults = ivM6MResultsFuture.get();
Map<String, Double> ivM12MResults = ivM12MResultsFuture.get();
Map<String, Double> iv2M6MResults = iv2M6MResultsFuture.get();
Map<String, Double> iv2M12MResults = iv2M12MResultsFuture.get();
Map<String, Double> iv2M24MResults = iv2M24MResultsFuture.get();
Map<String, Double> hvM6MResults = hvM6MResultsFuture.get();
Map<String, Double> hvM12MResults = hvM12MResultsFuture.get();
Map<String, Double> hv2M6MResults = hv2M6MResultsFuture.get();
Map<String, Double> hv2M12MResults = hv2M12MResultsFuture.get();
Map<String, Double> hv2M24MResults = hv2M24MResultsFuture.get();
使用大型for循环将所有未来映射到一起并汇总结果。希望从代码中清楚地了解它的作用,但基本上是:
两个主要问题:
您是否看到我的CompletableFuture使用存在任何问题,以及根据概述标准改进实施的任何空间,目前它比常规阻止速度慢2倍.get()旧期货,作为参考
我对加入完成的方式感到有些恼火,因为必须使用无效结果调用.allOf(),是否有更好的方法在我缺少的API中执行此操作。
作为一个旁注,我意识到我在Java8变体中做了一些工作,发生了一堆流和映射,但时间差从旧的22秒到新的45秒,总项目是关于200,所以大多数人实际上花在网络和等待而不是流操作上。
谢谢!
答案 0 :(得分:1)
很难说,因为代码的某些部分缺失,但我会避免使用.join()(因为它们阻塞),而是通过waitGroup迭代并使用combineAsync传递smths2。类似的东西:
Stream<CompletableFuture<AnotherData>> map =
waitGroup.stream().map(
cf -> cf.thenCombineAsync(
smths2, (m, l) -> {doWhatever(m, l)}
));
只是一个想法......