Java 如何重新排序CompletableFutures的流?
我处理的是一连串可完成的未来。这些需要不同的时间来完成。那些需要更长时间的块流处理,而其他人可能已经完成了(我知道并行流) 因此,我想重新排序流中的项目(例如,使用缓冲区),以向前移动已完成的期货 例如,如果一个getUser调用花费很长时间,则此代码会阻止流处理Java 如何重新排序CompletableFutures的流?,java,java-stream,completable-future,Java,Java Stream,Completable Future,我处理的是一连串可完成的未来。这些需要不同的时间来完成。那些需要更长时间的块流处理,而其他人可能已经完成了(我知道并行流) 因此,我想重新排序流中的项目(例如,使用缓冲区),以向前移动已完成的期货 例如,如果一个getUser调用花费很长时间,则此代码会阻止流处理 public static Boolean isValid(User user) { ... } emails.stream() // not using :: // getUser() returns Completa
public static Boolean isValid(User user) { ... }
emails.stream()
// not using ::
// getUser() returns CompletableFuture<User>
.map( e -> getUser(e))
// this line blocks Stream processing
.filter( userF -> isValid( userF.get()) )
.map( f -> f.thenApply(User::getName))
[1] 例如,CompletionService在调用take()时返回已完成的任务,否则返回块。但是CompletionService不接受未来,是否需要执行cs.sumbit(()->f.get())呢
我该怎么做
[编辑]
有更多的背景肯定会有助于调整答案——我感觉问题在其他地方,可以以更简单的方式解决 但如果你的问题是如何在一开始就以某种方式保持已完成的期货,那么有几种选择:
使用自定义的
比较器对流进行排序
:
.sorted(Comparator.comparing(f -> !f.isDone()))
请记住,isDone
不仅在未来成功完成时返回true
在
优先队列中存储期货
PriorityQueue<CompletableFuture<String>> queue
= new PriorityQueue<>(Comparator.comparing(f -> !f.isDone()));
有更多的背景肯定会有助于调整答案——我感觉问题在其他地方,可以以更简单的方式解决 但如果你的问题是如何在一开始就以某种方式保持已完成的期货,那么有几种选择:
使用自定义的
比较器对流进行排序
:
.sorted(Comparator.comparing(f -> !f.isDone()))
请记住,isDone
不仅在未来成功完成时返回true
在
优先队列中存储期货
PriorityQueue<CompletableFuture<String>> queue
= new PriorityQueue<>(Comparator.comparing(f -> !f.isDone()));
我假设OP中的需求是并发执行
getUser
,并按完成顺序处理结果。以下是执行完成服务的解决方案:
final CompletionService<User> ecs = new ExecutorCompletionService<>(executor);
emails.stream().map(e -> ecs.submit(() -> getUser(e).get()))
.collect(Collectors.collectingAndThen(Collectors.toList(), fs -> fs.stream())) // collect the future list for concurrent execution
.map(f -> {
try {
return ecs.take().get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
})
.filter(u -> isValid(u)).map(User::getName)... //TODO;
final CompletionService ecs=新的ExecutionCompletionService(executor);
emails.stream().map(e->ecs.submit(()->getUser(e.get()))
.collect(Collectors.collectingAndThen(Collectors.toList(),fs->fs.stream())//收集未来列表以供并发执行
.map(f->{
试一试{
返回ecs.take().get();
}捕获(中断异常|执行异常e){
抛出新的运行时异常(e);
}
})
.filter(u->isValid(u)).map(用户::getName)//待办事项;
或:
final BlockingQueue=new ArrayBlockingQueue(emails.size());
final CompletionService ecs=新的ExecutionCompletionService(执行者,队列);
emails.stream().forEach(e->ecs.submit(()->getUser(e.get());
IntStream.range(0,emails.size())
.mapToObj(i->{
试一试{
返回queue.poll().get();
}捕获(中断异常|执行异常e){
抛出新的运行时异常(e);
}
})
.filter(u->isValid(u)).map(User::getName);
这很简单,但并不简单。我假设OP中的需求是并发执行
getUser
,并按完成顺序处理结果。以下是执行完成服务的解决方案:
final CompletionService<User> ecs = new ExecutorCompletionService<>(executor);
emails.stream().map(e -> ecs.submit(() -> getUser(e).get()))
.collect(Collectors.collectingAndThen(Collectors.toList(), fs -> fs.stream())) // collect the future list for concurrent execution
.map(f -> {
try {
return ecs.take().get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
})
.filter(u -> isValid(u)).map(User::getName)... //TODO;
final CompletionService ecs=新的ExecutionCompletionService(executor);
emails.stream().map(e->ecs.submit(()->getUser(e.get()))
.collect(Collectors.collectingAndThen(Collectors.toList(),fs->fs.stream())//收集未来列表以供并发执行
.map(f->{
试一试{
返回ecs.take().get();
}捕获(中断异常|执行异常e){
抛出新的运行时异常(e);
}
})
.filter(u->isValid(u)).map(用户::getName)//待办事项;
或:
final BlockingQueue=new ArrayBlockingQueue(emails.size());
final CompletionService ecs=新的ExecutionCompletionService(执行者,队列);
emails.stream().forEach(e->ecs.submit(()->getUser(e.get());
IntStream.range(0,emails.size())
.mapToObj(i->{
试一试{
返回queue.poll().get();
}捕获(中断异常|执行异常e){
抛出新的运行时异常(e);
}
})
.filter(u->isValid(u)).map(User::getName);
这很简单,但并不简单。为什么不使用
CompletableFuture::thenapplysync
?更改示例以添加筛选器(),使其更清晰。为什么不尝试..stream.parallel()…?为什么不使用CompletableFuture::thenapplysync
?更改示例以添加筛选器(),使其更清晰。为什么不尝试..stream.parallel()…?使用这样的过滤器,在早期比较时,给定的未来对象F是否可能处于“进行中”状态,在稍后比较时是否可能处于“完成”状态?我想我还记得Java中的默认排序,当这种事情发生时(例如,它在非法状态下失败),比如。但也许我的记忆不准确,这只能发生在设计糟糕的比较算法上……谢谢你的回复。我不确定sorted是否有效,因为调用sorted()时,大多数期货都没有完成,流也没有排序。关于PriorityQueue:那么收集器将添加到PriorityQueue?如何将优先级队列再次转换为流?@StephanSchmidt streams是不可重用的迭代器,因此您始终需要不断创建新实例以获取最新快照-可以从PriorityQueue创建流,但基本相同problem@GPI对这是可能的,但情况总是如此,因为计算需要非零时间,在这段时间内,其他一些计算可能会完成
final BlockingQueue<Future<User>> queue = new ArrayBlockingQueue<>(emails.size());
final CompletionService<User> ecs = new ExecutorCompletionService<>(executor, queue);
emails.stream().forEach(e -> ecs.submit(() -> getUser(e).get()));
IntStream.range(0, emails.size())
.mapToObj(i -> {
try {
return queue.poll().get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
})
.filter(u -> isValid(u)).map(User::getName);