我有一个用例,其中我想根据对元素执行的网络调用来过滤列表中的几个元素。为此,我使用了流,过滤器和Completable Future。目标是执行异步执行,以使操作变得高效。伪代码将在下面提到。
public List<Integer> afterFilteringList(List<Integer> initialList){
List<Integer> afterFilteringList =initialList.stream().filter(element -> {
boolean valid = true;
try{
valid = makeNetworkCallAndCheck().get();
} catch (Exception e) {
}
return valid;
}).collect(Collectors.toList());
return afterFilteringList;
}
public CompletableFuture<Boolean> makeNetworkCallAndCheck(Integer value){
return CompletableFuture.completedFuture(resultOfNetWorkCall(value);
}
我在这里遇到的问题是,我自己是否以异步方式执行此操作?(因为我在过滤器中使用“ get”功能会阻止执行并使其仅顺序执行)还是存在在Java 8中使用Completable Future和Filters以异步方式完成此操作的更好方法。
答案 0 :(得分:6)
立即调用get
时,确实在破坏异步执行的好处。解决方案是在加入之前先收集所有异步作业。
public List<Integer> afterFilteringList(List<Integer> initialList){
Map<Integer,CompletableFuture<Boolean>> jobs = initialList.stream()
.collect(Collectors.toMap(Function.identity(), this::makeNetworkCallAndCheck));
return initialList.stream()
.filter(element -> jobs.get(element).join())
.collect(Collectors.toList());
}
public CompletableFuture<Boolean> makeNetworkCallAndCheck(Integer value){
return CompletableFuture.supplyAsync(() -> resultOfNetWorkCall(value));
}
当然,方法makeNetworkCallAndCheck
也必须启动真正的异步操作。同步调用方法并返回completedFuture
是不够的。我在这里提供了一个简单的示例性异步操作,但是对于I / O操作,您可能想提供自己的Executor
,以适合您希望允许的同时连接数。
答案 1 :(得分:1)
如果您使用get()
,它将不是异步
get()
:等待该将来完成,然后返回结果。
如果要在异步中处理所有请求。您可以使用CompletetableFuture.allOf()
public List<Integer> filterList(List<Integer> initialList){
List<Integer> filteredList = Collections.synchronizedList(new ArrayList());
AtomicInteger atomicInteger = new AtomicInteger(0);
CompletableFuture[] completableFutures = new CompletableFuture[initialList.size()];
initialList.forEach(x->{
completableFutures[atomicInteger.getAndIncrement()] = CompletableFuture
.runAsync(()->{
if(makeNetworkCallAndCheck(x)){
filteredList.add(x);
}
});
});
CompletableFuture.allOf(completableFutures).join();
return filteredList;
}
private Boolean makeNetworkCallAndCheck(Integer value){
// TODO: write the logic;
return true;
}
答案 2 :(得分:0)
Collection.parallelStream()
是对集合执行异步处理的一种简单方法。您可以按以下方式修改代码:
public List<Integer> afterFilteringList(List<Integer> initialList){
List<Integer> afterFilteringList =initialList
.parallelStream()
.filter(this::makeNetworkCallAndCheck)
.collect(Collectors.toList());
return afterFilteringList;
}
public Boolean makeNetworkCallAndCheck(Integer value){
return resultOfNetWorkCall(value);
}
您可以通过this way自定义自己的执行器。并且根据this确保结果顺序。
我已编写以下代码来验证我的发言。
public class DemoApplication {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinPool forkJoinPool = new ForkJoinPool(50);
final List<Integer> integers = new ArrayList<>();
for (int i = 0; i < 50; i++) {
integers.add(i);
}
long before = System.currentTimeMillis();
List<Integer> items = forkJoinPool.submit(() ->
integers
.parallelStream()
.filter(it -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
})
.collect(Collectors.toList()))
.get();
long after = System.currentTimeMillis();
System.out.println(after - before);
}
}
我创建了自己的ForkJoinPool
,尽管每项花费10000毫秒,但我花了10019毫秒来并行完成50个作业。