简体   繁体   English

使用CompletableFuture.supplyAsync返回多个值

[英]Returning multiple values with CompletableFuture.supplyAsync

I am writing a program to download historical quotes from a source. 我正在编写一个程序以从源代码下载历史报价。 The source provides files over http for each day which need to be parsed and processed. 源每天通过http提供需要解析和处理的文件。 The program downloads multiple files in parallel using a CompletableFuture using different stages. 该程序使用CompletableFuture不同阶段并行下载多个文件。 The first stage is to make a Http call using HttpClient and get the response. 第一步是使用HttpClient进行Http调用并获取响应。

The getHttpResponse() method returns a CloseableHttpResponse Object. getHttpResponse()方法返回一个CloseableHttpResponse对象。 I also want to return a url for which this http request was made. 我还想返回为此http请求发出的URL。 Simplest way is to have a wrapper object having these 2 fields, but i feel it is too much to have a class just to contain these 2 fields. 最简单的方法是让包装对象具有这两个字段,但是我觉得拥有一个仅包含这两个字段的类实在太多了。 Is there a way with CompletableFuture or Streams that I can achieve this? 使用CompletableFuture或Streams是否可以实现这一目标?

  filesToDownload.stream()
                 .map(url -> CompletableFuture.supplyAsync(() -> this.getHttpResponse(url), this.executor) )
                 .map(httpResponseFuture -> httpResponseFuture.thenAccept(t -> processHttpResponse(t)))
                 .count();

It's not clear why you want to bring in the Stream API at all costs. 目前尚不清楚为什么要不惜一切代价引入Stream API。 Splitting the CompletableFuture use into two map operations causes the problem which wouldn't exist otherwise. CompletableFuture用途分为两个map操作会导致该问题,否则该问题将不存在。 Besides that, using map for side effects is an abuse of the Stream API. 除此之外,使用map产生副作用是对Stream API的滥用。 This may break completely in Java 9, if filesToDownload is a Stream source with a known size (like almost every Collection). 如果filesToDownload是具有已知大小(类似于几乎每个Collection)的Stream源,则在Java 9中可能会完全中断。 Then, count() will simply return that known size, without processing the functions of the map operations… 然后, count()将简单地返回该已知大小,而无需处理map操作的功能…

If you want to pass the URL and the CloseableHttpResponse to processHttpResponse , you can do it as easy as: 如果要将URLCloseableHttpResponseprocessHttpResponse ,则可以像以下操作一样简单:

filesToDownload.forEach(url ->
    CompletableFuture.supplyAsync(() -> this.getHttpResponse(url), this.executor)
                     .thenAccept(  t -> processHttpResponse(t, url))
);

Even, if you use the Stream API to collect results, there is no reason to split the CompletableFuture into multiple map operations: 即使使用Stream API收集结果,也没有理由将CompletableFuture拆分为多个map操作:

List<…> result = filesToDownload.stream()
  .map(url -> CompletableFuture.supplyAsync(() -> this.getHttpResponse(url), this.executor)
                               .thenApply(   t -> processHttpResponse(t, url))  )
  .collect(Collectors.toList())
  .stream()
  .map(CompletableFuture::join)
  .collect(Collectors.toList());

Note that this will collect the CompletableFuture s into a List before waiting for any result in a second Stream operation. 请注意,在等待第二次Stream操作的任何结果之前,这会将CompletableFuture收集到List中。 This is preferable to using a parallel Stream operation as it ensures that all asynchronous operations have been submitted, before starting to wait. 这比使用并行Stream操作更可取,因为它可以确保在开始等待之前已提交所有异步操作。

Using a single Stream pipeline would imply waiting for the completion of the first job before even submitting the second and using a parallel Stream would only reduce that problem instead of solving it. 使用单个Stream管道意味着甚至在提交第二个任务之前也要等待第一个任务的完成,而使用并行Stream只会减少而不是解决该问题。 It would depend on the execution strategy of the Stream implementation (the default Fork/Join pool), which interferes with actual policy of your specified executor. 这将取决于Stream实现的执行策略(默认的Fork / Join池),这会干扰您指定的执行者的实际策略。 Eg, if the specified executor is supposed to use more threads than CPU cores, the Stream would still submit only as much jobs at a time as there are cores — or even less if there are other jobs on the default Fork/Join pool. 例如,如果指定的执行程序使用的线程多于CPU内核,则Stream一次只能提交与内核数量一样多的作业-如果默认的Fork / Join池中还有其他作业,则提交的线程甚至更少。

In contrast, the behavior of the solution above will be entirely controlled by the execution strategy of the specified executor. 相反,以上解决方案的行为将完全由指定执行者的执行策略控制。

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

相关问题 使用 Mockito 测试 CompletableFuture.supplyAsync - Testing CompletableFuture.supplyAsync with Mockito ForkJoinPool在CompletableFuture.supplyAsync()中的行为 - Behaviour of ForkJoinPool in CompletableFuture.supplyAsync() CompletableFuture.supplyAsync() 没有 Lambda - CompletableFuture.supplyAsync() without Lambda 获取CompletableFuture.supplyAsync的结果 - Getting the result of a CompletableFuture.supplyAsync CompletableFuture.supplyAsync与新的CompletableFuture() - CompletableFuture.supplyAsync vs new CompletableFuture() 简单的 CompletableFuture.supplyAsync() 导致 IllegalMonitorStateException 错误 - Simple CompletableFuture.supplyAsync() leads to IllegalMonitorStateException error CompletableFuture.supplyAsync 代码的代码覆盖率 - code coverage of CompletableFuture.supplyAsync code 如何将CompletableFuture.supplyAsync与PriorityBlockingQueue一起使用? - How do I use CompletableFuture.supplyAsync together with PriorityBlockingQueue? JDK8 CompletableFuture.supplyAsync 如何处理interruptedException - JDK8 CompletableFuture.supplyAsync how to deal with interruptedException 如何将completableFuture.supplyAsync()的返回类型分配给对象? - how to assign the return type of completableFuture.supplyAsync() to the object?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM