繁体   English   中英

使用CompletableFuture.supplyAsync返回多个值

[英]Returning multiple values with CompletableFuture.supplyAsync

我正在编写一个程序以从源代码下载历史报价。 源每天通过http提供需要解析和处理的文件。 该程序使用CompletableFuture不同阶段并行下载多个文件。 第一步是使用HttpClient进行Http调用并获取响应。

getHttpResponse()方法返回一个CloseableHttpResponse对象。 我还想返回为此http请求发出的URL。 最简单的方法是让包装对象具有这两个字段,但是我觉得拥有一个仅包含这两个字段的类实在太多了。 使用CompletableFuture或Streams是否可以实现这一目标?

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

目前尚不清楚为什么要不惜一切代价引入Stream API。 CompletableFuture用途分为两个map操作会导致该问题,否则该问题将不存在。 除此之外,使用map产生副作用是对Stream API的滥用。 如果filesToDownload是具有已知大小(类似于几乎每个Collection)的Stream源,则在Java 9中可能会完全中断。 然后, count()将简单地返回该已知大小,而无需处理map操作的功能…

如果要将URLCloseableHttpResponseprocessHttpResponse ,则可以像以下操作一样简单:

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

即使使用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());

请注意,在等待第二次Stream操作的任何结果之前,这会将CompletableFuture收集到List中。 这比使用并行Stream操作更可取,因为它可以确保在开始等待之前已提交所有异步操作。

使用单个Stream管道意味着甚至在提交第二个任务之前也要等待第一个任务的完成,而使用并行Stream只会减少而不是解决该问题。 这将取决于Stream实现的执行策略(默认的Fork / Join池),这会干扰您指定的执行者的实际策略。 例如,如果指定的执行程序使用的线程多于CPU内核,则Stream一次只能提交与内核数量一样多的作业-如果默认的Fork / Join池中还有其他作业,则提交的线程甚至更少。

相反,以上解决方案的行为将完全由指定执行者的执行策略控制。

暂无
暂无

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

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