Java 8 CompletableFuture - 扇出实现

时间:2015-02-20 04:41:00

标签: java asynchronous lambda future

我想知道在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循环将所有未来映射到一起并汇总结果。希望从代码中清楚地了解它的作用,但基本上是:

  1. 我进行了一次获取列表的网络电话
  2. 根据此列表i 调用生成一些对象的内部服务
  3. 基于第一个列表,我产生了一堆任务来获取各种数据
  4. 我使用3中的项填充2中生成的对象 - 基本上2和3可以同时运行,因为它们不是 依赖性的。
  5. 两个主要问题:

    1. 您是否看到我的CompletableFuture使用存在任何问题,以及根据概述标准改进实施的任何空间,目前它比常规阻止速度慢2倍.get()旧期货,作为参考

    2. 我对加入完成的方式感到有些恼火,因为必须使用无效结果调用.allOf(),是否有更好的方法在我缺少的API中执行此操作。

    3. 作为一个旁注,我意识到我在Java8变体中做了一些工作,发生了一堆流和映射,但时间差从旧的22秒到新的45秒,总项目是关于200,所以大多数人实际上花在网络和等待而不是流操作上。

      谢谢!

1 个答案:

答案 0 :(得分:1)

很难说,因为代码的某些部分缺失,但我会避免使用.join()(因为它们阻塞),而是通过waitGroup迭代并使用combineAsync传递smths2。类似的东西:

    Stream<CompletableFuture<AnotherData>> map = 
         waitGroup.stream().map(
                cf -> cf.thenCombineAsync(
                       smths2, (m, l) -> {doWhatever(m, l)}
    ));

只是一个想法......