关于使用CompletableFuture的建议

huangapple 未分类评论62阅读模式
标题翻译

Advice on using CompletableFuture

问题

我想就如何有效使用CompletableFuture给予一些建议。

如果我有一个整数列表,对于其中的每个整数,我想执行3个动作,这需要一些时间。例如,乘法、除法和减法。

对于结果,它应该是一个映射(map),其中键是整数,值是一个包含三个动作结果的列表。

场景1:如果我想要在完成处理一个整数后将结果写入映射中,那么以下方法是一个不错的做法吗?

for (int x : nums) {
  CompletableFuture<Integer> multiply = CompletableFuture.supplyAsync(() -> multiply(x));
  CompletableFuture<Integer> divide = CompletableFuture.supplyAsync(() -> divide(x));
  CompletableFuture<Integer> subtract = CompletableFuture.supplyAsync(() -> subtract(x));
  
  CompletableFuture<Void> allRequests = CompletableFuture.allOf(multiply, divide, subtract);
  
  // 遍历这三个CompletableFuture并添加到映射中。
}

场景2:如果我想要在所有过程完成之前将结果写入映射中。

List<CompletableFuture<Void>> allRequests = new ArrayList<>();

for (int x : nums) {
  CompletableFuture<Integer> multiply = CompletableFuture.supplyAsync(() -> multiply(x));
  CompletableFuture<Integer> divide = CompletableFuture.supplyAsync(() -> divide(x));
  CompletableFuture<Integer> subtract = CompletableFuture.supplyAsync(() -> subtract(x));
  
  CompletableFuture<Void> allRequestsPerNum = CompletableFuture.allOf(multiply, divide, subtract);

  allRequests.add(allRequestsPerNum);
}

CompletableFuture.allOf(allRequests);

// 我该如何构建结果?

对于场景2,看起来如果我们在for循环内调用CompletableFuture.allOf,这意味着在继续处理下一个数字之前,这三个动作都需要完成?

英文翻译

I would like some advice on good ways to use CompletableFuture.

If I have a list of integers, for each of them, I would like to perform 3 actions, which takes some time. For example, multiply, divide and subtract.

For the result, it should be map, where key is the integer and the value is list that has the result of three actions.

Scenario 1: If I want to write the result to the map once we finish process one integer, then is below the a good way to do it?

for (int x : nums) {
  CompletableFuture&lt;Integer&gt; multiply = CompletableFuture.supplyAsync(() -&gt; multiply(x));
  CompletableFuture&lt;Integer&gt; divide = CompletableFuture.supplyAsync(() -&gt; divide(x));
  CompletableFuture&lt;Integer&gt; subtract = CompletableFuture.supplyAsync(() -&gt; subtract(x));
  
  CompletableFuture&lt;Void&gt; allRequests = CompletableFuture.allOf(multiple, divide, substract);
  
  //iterate the three CompletableFuture and add to the map.
}

Scenario 2: If I want to write the result to the map until all the process is done.

List&lt;CompletableFuture&lt;Void&gt;&gt; allRequests = new ArrayList&lt;&gt;();

for (int x : nums) {
  CompletableFuture&lt;Integer&gt; multiply = CompletableFuture.supplyAsync(() -&gt; multiply(x));
  CompletableFuture&lt;Integer&gt; divide = CompletableFuture.supplyAsync(() -&gt; divide(x));
  CompletableFuture&lt;Integer&gt; subtract = CompletableFuture.supplyAsync(() -&gt; subtract(x));
  
  CompletableFuture&lt;Void&gt; allRequestsPerNum = CompletableFuture.allOf(multiple, divide, substract);

  allRequests.add(allRequestsPerNum);
}

CompletableFuture.allOf(allRequest);

//How am I suppose to build the result?

For scenario 2, it looks like if we call CompletableFuture.allOf inside the for loop, it implies the three actions need to be done before we move to the next number?

答案1

得分: 0

您可以使用`CompletableFuture`中内置的功能尚未经过测试因此可能会出现一些小问题但应该能够给您一个相当好的想法

List<CompletableFuture<Void>> allRequests = new ArrayList<>();

for (int x : nums) {
     allRequests.add(CompletableFuture.allOf(
            CompletableFuture.supplyAsync(() -> multiply(x)).thenApplyAsync(() -> addToMap()),
            CompletableFuture.supplyAsync(() -> divide(x)).thenApplyAsync(() -> addToMap()),
            CompletableFuture.supplyAsync(() -> subtract(x)).thenApplyAsync(() -> addToMap())));
}
CompletableFuture.allOf(allRequests.toArray(new CompletableFuture[])).join();
英文翻译

You can use the features build into CompletableFuture, untested so there are probably some minor problems. It should give you a decent idea.

    List&lt;CompletableFuture&lt;Void&gt;&gt; allRequests = new ArrayList&lt;&gt;();

    for (int x : nums) {
         allRequests.add(CompletableFuture.allOf(
                CompletableFuture.supplyAsync(() -&gt; multiply(x)).thenApplyAsync(() -&gt; addToMap()),
                CompletableFuture.supplyAsync(() -&gt; divide(x)).thenApplyAsync(() -&gt; addToMap()),
                CompletableFuture.supplyAsync(() -&gt; subtract(x)).thenApplyAsync(() -&gt; addToMap())));
    }
    CompletableFuture.allOf(allRequests.toArray(new CompletableFuture[])).join();

答案2

得分: 0

以下代码可能适用于您:

正如评论中所提到的,我不能保证以这种方式做事情会带来任何性能上的好处。我也不能保证这是一个'最佳实践'。

// 保持所有的 futures
final Collection<CompletableFuture<?>> futures = new ArrayList<>();

// 准备结果映射
final Map<Integer, List<Integer>> map = new HashMap<>();

for (int x : Arrays.asList(1, 2, 3)) {
    // 创建映射值 List。
    // 用一些默认值初始化它,以便'set'函数能够使用。
    // 使用一个并发安全的 List,以便异步操作不会导致数据损坏。
    final List<Integer> value = new CopyOnWriteArrayList<>(Arrays.asList(0, 0, 0));

    // 将键和 List(尚未准备好)放入映射中
    map.put(x, value);

    // 将所有的 futures 添加到您的追踪集合中。
    // 注意:现在每个 future 都包括将适当的结果设置到 List 中的条目。
    futures.add(CompletableFuture.supplyAsync(() -> 2 * x)
            .thenAcceptAsync(result -> value.set(0, result)));
    futures.add(CompletableFuture.supplyAsync(() -> 2 / x)
            .thenAcceptAsync(result -> value.set(1, result)));
    futures.add(CompletableFuture.supplyAsync(() -> 2 - x)
            .thenAcceptAsync(result -> value.set(2, result)));
}

// 等待它们全部完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
英文翻译

Something like the following should work for you:

As mentioned in the comments, I make no promises that there would be any performance benefit from doing things this way. I also make no promises this is a 'best practice' for doing it.

// Keep all the futures around
final Collection&lt;CompletableFuture&lt;?&gt;&gt; futures = new ArrayList&lt;&gt;();

// And prepare the resulting map
final Map&lt;Integer, List&lt;Integer&gt;&gt; map = new HashMap&lt;&gt;();

for (int x : Arrays.asList(1, 2, 3)) {
    // Create the map value List.
    // Initialise it with some default values so that &#39;set&#39;
    // works.  Use a concurrent-safe List so that there&#39;s
    // no risk of corruption from the async operations.
    final List&lt;Integer&gt; value = new CopyOnWriteArrayList&lt;&gt;(Arrays.asList(0, 0, 0));

    // Put the key and List (not yet ready) into the Map
    map.put(x, value);

    // Add all of your futures to your tracking Collection.
    // Note: each future now includes setting the appropriate
    // entry in the List to that result.
    futures.add(CompletableFuture.supplyAsync(() -&gt; 2 * x)
            .thenAcceptAsync(result -&gt; value.set(0, result)));
    futures.add(CompletableFuture.supplyAsync(() -&gt; 2 / x)
            .thenAcceptAsync(result -&gt; value.set(1, result)));
    futures.add(CompletableFuture.supplyAsync(() -&gt; 2 - x)
            .thenAcceptAsync(result -&gt; value.set(2, result)));
}

// Wait for them all to complete.
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

huangapple
  • 本文由 发表于 2020年3月4日 08:10:28
  • 转载请务必保留本文链接:https://java.coder-hub.com/60517339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定