繁体   English   中英

如何使用 join 完成 CompletableFuture

[英]How to use join for complete CompletableFuture

据说我有以下方法

public static Stream<CompletableFuture<String>> findPricesStream(String product) {}

此方法将查找给定product的最便宜价格,并返回 CompletableFuture 的 stream。

现在我想在 stream 中的值可用时立即做出反应。 为此,我采用thenAccept方法,实现如下

    1. public static void reactToEarliestResultWithRaw() {
    2.     long start = System.nanoTime();
    3.     CompletableFuture[] priceFuture = findPricesStream(WHATEVER_PRODUCT_NAME)
    4.             .map(completableFuture -> completableFuture.thenAccept(
    5.                     s -> System.out.println(s + " (done in " + (System.nanoTime() - start) / 1_000_000 + " msecs)")))
    6.             .toArray(CompletableFuture[]::new);
    7.     CompletableFuture.allOf(priceFuture).join();
    8.     System.out.println("All shops have now responded in " + (System.nanoTime() - start) / 1_000_000 + " msecs)");
    9. }

通过这个实现,我得到了想要的 output

LetsSaveBig price is 151.227 (done in 5476 msecs)
BuyItAll price is 211.66 (done in 5747 msecs)
MyFavoriteShop price is 206.30200000000002 (done in 6968 msecs)
BestPrice price is 131.917 (done in 8110 msecs)
All shops have now responded in 8110 msecs)

现在我想进一步让代码更具可读性。 我链接了另一个负责加入所有 CompletableFuture 的 map

    1. public static void reactToEarliestResultWithoutRaw() {
    2.     long start = System.nanoTime();
    3.     List<Void> completeFutures = findPricesStream(WHATEVER_PRODUCT_NAME)
    4.             .map(completableFuture -> completableFuture.thenAccept(
    5.                     s -> System.out.println(s + " (done in " + (System.nanoTime() - start) / 1_000_000 + " msecs)")))
    6.             .map(CompletableFuture::join)
    7.             .toList();
    8.     int size = completeFutures.size();
    9.     if (isComplete(size)) {
    10.         System.out.println("All shops have now responded in " + (System.nanoTime() - start) / 1_000_000 + " msecs)");
    11. }
    12.
    13. private static boolean isComplete(int size) {
    14.     return size == shops.size();
    15. }    

我得到了 output

BestPrice price is 123.17400000000002 (done in 2060 msecs)
LetsSaveBig price is 109.67200000000001 (done in 6025 msecs)
MyFavoriteShop price is 131.21099999999998 (done in 13860 msecs)
BuyItAll price is 164.392 (done in 18434 msecs)
All shops have now responded in 18434 msecs)

结果让我吃惊! 我希望两者的经过时间应该是相同的,但它们是一个巨大的差异。

我在这里误解了使用join的方式吗?

参考

该实现来自《 Modern Java in Action: Lambdas, streams, functional and reactive programming 2nd Edition 》一书,我为实验做了一些修改。

“令人惊讶”的结果是由于findPricesStream是如何实现的:它返回shops.stream().map(shop -> CompletableFuture.supplyAsync(...) 。直到将终端操作应用于返回的 stream 才构造 CompletableFuture . 这是在你调用.toList()之后在你自己的方法中完成的。

终端操作toList()这样做:

  1. 对于第一个shop ,它构造了一个CompletableFuture ,它开始运行。
  2. CompletableFuture 被加入,即主线程等待完成。
  3. 然后为下一个商店构造下一个 CompletableFuture,以此类推。

所以价格是按顺序计算的。 要使计算并行运行,首先创建列表(以便启动所有期货),然后加入它们:

3.     List<Void> completeFutures = findPricesStream(WHATEVER_PRODUCT_NAME)
4.             .map(completableFuture -> completableFuture.thenAccept(
5.                     s -> System.out.println(s + " (done in " + (System.nanoTime() - start) / 1_000_000 + " msecs)")))
6.             .toList();
7.     completeFutures.foreach(CompletableFuture::join);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM