[英]Reduce List<CompletableFuture<T>>
當給出ints
時:
List<Integer> ints = IntStream.range(0, 1000).boxed().collect(Collectors.toList());
使用 Java Stream API,我們可以減少它們
MyValue myvalue = ints
.parallelStream()
.map(x -> toMyValue(x))
.reduce((t, t2) -> t.combine(t2))
.get();
在這個例子中,對我來說重要的是......
toMyValue()
的所有結果都會同時加載現在我想通過CompletableFuture
API 做同樣的處理。
要做 map,我做了:
List<CompeletableFuture<MyValue>> myValueFutures = ints
.stream()
.map(x -> CompletableFuture.supplyAsync(() -> toMyValue(x), MY_THREAD_POOL))
.collect(Collectors.toList());
現在我不知道如何減少List<CompeletableFuture<MyValue>> myValueFutures
以獲得單個MyValue
。
並行 stream 提供了方便的 API,但由於這些問題,我不想使用 Stream API:
有什么方法可以減少 CompetableFutures? 一一去掉 stream 減少 api?
有趣的是,在您的初始示例中,您已經提到了一個方法combine
,而CompletableFuture
有一個專用方法,僅用於此: thenCombine
(及其兩個兄弟thenCombineAsync
)。
所以考慮到你有類似的東西:
static class MyValue {
final int x;
MyValue(int x) {
this.x = x;
}
MyValue combine(MyValue v){
return new MyValue(this.x + v .x);
}
}
static MyValue toMyValue(int x) {
return new MyValue(x);
}
和:
List<CompletableFuture<Integer>> list =
IntStream.range(0, 4)
.mapToObj(x -> supplyAsync(() -> x))
.collect(Collectors.toList());
您可以使用其中一種thenCombine
方法並通過以下方式實現您想要的:
MyValue value =
list.stream()
.map(x -> x.thenApply(YourClass::toMyValue))
.reduce((left, right) -> left.thenCombine(right, MyValue::combine))
.orElse(CompletableFuture.completedFuture(new MyValue(0)))
.join();
如果要在可預測的線程中執行組合操作,則需要一個池或重載方法,例如:
.reduce((left, right) -> left.thenCombineAsync(right, MyValue::combine, MY_THREAD_POOL))
基本上,您需要等待所有CompletableFuture
的結果,然后組合以獲得所需的結果。
為此有多種方法,但CompletableFuture
allOf
提供了可用於該目的的 allOf 方法。
當我不得不處理類似的問題時,我喜歡遵循 Tomasz Nurkiewicz 的建議並以下列方式執行這種計算。
正如文章中所建議的,首先,讓我們定義以下方便的方法: allOf
接收 arguments 作為可變參數,並且不返回聚合結果的未來; 此方法將允許您克服這些缺點,因此您可以將Collection
作為參數傳遞並返回實際結果的List
而不是Void
。
private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
CompletableFuture<Void> allDoneFuture =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
return allDoneFuture.thenApply(v ->
futures.stream().
map(future -> future.join()).
collect(Collectors.<T>toList())
);
}
使用這種方便的方法,您可以通過以下方式減少您的值:
final CompletableFuture<List<MyValue>> allDone = sequence(myValueFutures);
// Please, see also for alternate approaches
// https://stackoverflow.com/questions/43489281/return-value-directly-from-completablefuture-thenaccept
final List<MyValue> myValues = allDone.join();
final Optional<MyValue> optResult = myValues.stream().
reduce((t, t2) -> t.combine(t2))
;
// Process the returned value as you consider appropriate
final MyValue result = optResult.get();
static BiFunction<Airline,Integer,Double> getTotalDelay=(airline,year)-> airline
.getFlights().stream()
.filter(flight ->flight.getScheduledDeparture().getYear()==year)
.mapToDouble(f->calcFlightDelay.apply(f)).average().orElse(0.0);
//todo: Implement the following function
static TriFunction<List<Airline>,Integer,Integer,List<String>> lowestDelaysAirlines=
(airlins,year,k)->airlins.stream()
.sorted((a1,a2)->(int)(getTotalDelay.apply(a1,year)-getTotalDelay.apply(a2,year)))
.map(al -> al.getName()).limit(k)
.collect(Collectors.toList());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.