Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 筛选出重复项以备将来完成_Java_Java Stream_Distinct_Completable Future - Fatal编程技术网

Java 筛选出重复项以备将来完成

Java 筛选出重复项以备将来完成,java,java-stream,distinct,completable-future,Java,Java Stream,Distinct,Completable Future,我想过滤掉第一个CompletableFuture之后的重复项,然后使用另一个CompletableFuture调用第二个阶段。我尝试的是: @FunctionalInterface public interface FunctionWithExceptions<T, R, E extends Exception> { R process(T t) throws E; } public static <T> Predicate<T> distinc

我想过滤掉第一个
CompletableFuture
之后的重复项,然后使用另一个
CompletableFuture
调用第二个阶段。我尝试的是:

@FunctionalInterface
public interface FunctionWithExceptions<T, R, E extends Exception> {
    R process(T t) throws E;
}


public static <T> Predicate<T> distinctByKey(FunctionWithExceptions<? super T, ?, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> {
        String key = "";
        try {
            key = (String) keyExtractor.process(t);
        } catch (Exception e) {
            log.info("Get instanceIp failed!");
        }
        return seen.add(key);
    };
}

List<CompletableFuture<InstanceDo>> instanceFutures = podNames.stream()
            .map(podName -> CompletableFuture.supplyAsync(RethrowExceptionUtil.rethrowSupplier(() -> {
                PodDo podDo = getPodRetriever().getPod(envId, podName);
                podDoList.add(podDo);
                return podDo;
            }), executor))
            .map(future -> future.thenApply(podDo -> podDo.getInstanceName()))
            .filter(distinctByKey(CompletableFuture::get))
            .map(future -> future.thenCompose(instanceName ->
                    CompletableFuture.supplyAsync(() -> get(envId, instanceName), executor)))
            .collect(Collectors.toList());
@functioninterface
公共接口功能,无例外{
R过程(T)抛出E;
}
公共静态谓词distinctByKey(带有异常的函数keyExtractor){
Set seen=ConcurrentHashMap.newKeySet();
返回t->{
字符串键=”;
试一试{
key=(String)keydextractor.process(t);
}捕获(例外e){
log.info(“GetInstanceIP失败!”);
}
返回所见。添加(键);
};
}
List instanceFutures=podNames.stream()
.map(podName->CompletableFuture.supplyAsync(RethrowExceptionUtil.RethrowsSupplier)(()->{
PodDo PodDo=getPodRetriever().getPod(envId,podName);
podDoList.add(podDo);
返回podDo;
})(执行人)
.map(future->future.thenappy(podDo->podDo.getInstanceName())
.filter(distinctByKey(CompletableFuture::get))
.map(未来->未来->合成(instanceName->
CompletableFuture.supplyAsync(()->get(envId,instanceName),executor)))
.collect(Collectors.toList());
如您所见,
distinctByKey
调用
get
,这将直接使并发性成为顺序性

我应该怎么做才能使它再次并发,同时保留独特的功能

我只有一个选择


要等待整个第一阶段完成,然后开始第二阶段

我只是写了一个简单的演示来解决这种问题,但我真的不知道它是否可靠。但至少它确保可以使用
Set seen=ConcurrentHashMap.newKeySet()来加速第二阶段

public static void main(String... args) throws ExecutionException, InterruptedException {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        List<CompletableFuture<Integer>> intFutures = Stream.iterate(0, i -> i+1)
                .limit(5)
                .map(i -> CompletableFuture.supplyAsync(() -> {
                    int a = runStage1(i);
                    if (seen.add(a)) {
                        return a;
                    } else {
                        return -1;
                    }}))
                .map(future -> future.thenCompose(i -> CompletableFuture.supplyAsync(() -> {
                    if (i > 0) {
                        return runStage2(i);
                    } else {
                        return i;
                    }})))
                .collect(Collectors.toList());
        List<Integer> resultList = new ArrayList<>();
        try {
            for (CompletableFuture<Integer> future: intFutures) {
                resultList.add(future.join());
            }
        } catch (Exception ignored) {
            ignored.printStackTrace();
            out.println("Future failed!");
        }
        resultList.stream().forEach(out::println);
    }

    private static Integer runStage1(int a) {
        out.println("stage - 1: " + a);
        try {
            Thread.sleep(500 + Math.abs(new Random().nextInt()) % 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Integer.valueOf(a % 3);
    }

    private static Integer runStage2(int b) {
        out.println("stage - 2: " + b);
        try {
            Thread.sleep(200 + Math.abs(new Random().nextInt()) % 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return Integer.valueOf(b);
    }

我认为这不是一个好的解决办法。但是我可以优化什么使其更好呢?

与之相比,一个小小的改进可能是使用
ConcurrentHashMap
作为一种缓存,这样您的最终列表包含相同的结果,而与您获得它们的顺序无关:

Map<Integer, CompletableFuture<Integer>> seen = new ConcurrentHashMap<>();
List<CompletableFuture<Integer>> intFutures = Stream.iterate(0, i -> i + 1)
        .limit(5)
        .map(i -> CompletableFuture.supplyAsync(() -> runStage1(i)))
        .map(cf -> cf.thenCompose(result ->
                seen.computeIfAbsent(
                        result, res -> CompletableFuture.supplyAsync(() -> runStage2(res))
                )
        ))
        .collect(Collectors.toList());

此外,这允许在所有期货交易完成后检查
seen
地图,以获得唯一的结果。

小心,
然后应用
然后合成
是同步的。您可能更喜欢
然后是applyasync
然后是composeasync
@kagmole谢谢您的回复。但我不认为你明白这一点。我对*Async非常了解,因为它们有很好的文档记录。我希望第二个在第一个之后运行,然后在这里编写就足够了,因为它将在与第一个阶段相同的线程中工作。我明白了,而且仍然存在
distinctByKey
问题。我可能有一个基于
可选
的建议,但我担心它最终会不必要地膨胀。@kagmole谢谢你的建议,我会尝试一下。实际上,这是一个从一开始就截然不同的问题。哈哈,谢谢你,伙计。是的,对不起,我不是很清楚为什么你认为这不是一个好的解决方案?我看到的唯一问题是,结果列表包含第一阶段(
-1
)和第二阶段的混合结果,但您可以轻松地将它们过滤掉。您应该使用
ThreadLocalRandom.current()
而不是
new Random()
,因为它是线程安全的,并且是首选的替代方法。您的解决方案与我所想的类似,您只是使用了一个鉴别器值
-1
,而不是
可选的
,如果您能够做到这一点(无
可选的
开销),那就很好了。“不过我现在看不出有什么进步。”卡格莫尔谢谢你的帮助,我明白了重点,并用这种方式改进了它。此外,感谢使用线程安全随机的软提醒,我忘记了。谢谢~@didierr谢谢你的观点,我刚刚测试了它们,看起来不错。我的想法是,它可以更优雅——直接过滤,而不是在第二阶段检查然后过滤。
Map<Integer, CompletableFuture<Integer>> seen = new ConcurrentHashMap<>();
List<CompletableFuture<Integer>> intFutures = Stream.iterate(0, i -> i + 1)
        .limit(5)
        .map(i -> CompletableFuture.supplyAsync(() -> runStage1(i)))
        .map(cf -> cf.thenCompose(result ->
                seen.computeIfAbsent(
                        result, res -> CompletableFuture.supplyAsync(() -> runStage2(res))
                )
        ))
        .collect(Collectors.toList());
stage - 1: 1
stage - 1: 0
stage - 1: 2
stage - 2: 1
stage - 2: 2
stage - 1: 3
stage - 2: 0
stage - 1: 4
0
1
2
0
1