[英]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
操作的功能…
如果要将URL
和CloseableHttpResponse
给processHttpResponse
,则可以像以下操作一样简单:
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.