当前位置: 首页 > 知识库问答 >
问题:

完整的循环中的未来:如何收集所有响应并处理错误

戚明朗
2023-03-14

我试图在循环中调用PUT请求的rest api。每个调用都是一个CompletableFuture。每个api调用返回一个类型为RoomType的对象。房间类型

>

  • 我想收集不同列表中的响应(成功和错误响应)。我如何实现这一点?我确信我不能使用allOf,因为如果任何一个调用未能更新,它将无法获得所有结果。

    如何记录每次呼叫的错误/异常?


    public void sendRequestsAsync(Map<Integer, List> map1) {
        List<CompletableFuture<Void>> completableFutures = new ArrayList<>(); //List to hold all the completable futures
        List<RoomTypes.RoomType> responses = new ArrayList<>(); //List for responses
        ExecutorService yourOwnExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
        for (Map.Entry<Integer, List> entry :map1.entrySet()) { 
            CompletableFuture requestCompletableFuture = CompletableFuture
                    .supplyAsync(
                            () -> 
                //API call which returns object of type RoomTypes.RoomType
                updateService.updateRoom(51,33,759,entry.getKey(),
                               new RoomTypes.RoomType(entry.getKey(),map2.get(entry.getKey()),
                                        entry.getValue())),
                        yourOwnExecutor
                )//Supply the task you wanna run, in your case http request
                .thenApply(responses::add);
    
        completableFutures.add(requestCompletableFuture);
    }
    

  • 共有3个答案

    鞠侯林
    2023-03-14

    用于要使用For循环的位置。这是一个可行的解决办法。完全uture.all

    您希望下载一个网站的100个不同网页的内容。您可以按顺序执行此操作,但这将花费大量时间。因此,可以编写一个函数来获取网页链接,并返回一个完整的未来:

    CompletableFuture<String> downloadWebPage(String pageLink) {
    return CompletableFuture.supplyAsync(() -> {
        // Code to download and return the web page's content
    });
    } 
    

    在循环中调用上一个函数,我们使用的是JAVA 8

    List<String> webPageLinks = Arrays.asList(...)  // A list of 100 web page links
    
    // Download contents of all the web pages asynchronously
    List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
        .map(webPageLink -> downloadWebPage(webPageLink))
        .collect(Collectors.toList());
    
    
    // Create a combined Future using allOf()
    CompletableFuture<Void> allFutures = CompletableFuture.allOf(
        pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
    );
    

    未来的问题。allOf()是指它返回CompletableFuture。但是,通过编写几行额外的代码,我们可以得到所有包装的CompletableFutures的结果

    // When all the Futures are completed, call `future.join()` to get their results and collect the results in a list -
    CompletableFuture<List<String>> allPageContentsFuture = allFutures.thenApply(v -> {
    return pageContentFutures.stream()
           .map(pageContentFuture -> pageContentFuture.join())
           .collect(Collectors.toList());
    });
    

    现在让我们统计包含关键字的网页数量-

    // Count the number of web pages having the "CompletableFuture" keyword.
    CompletableFuture<Long> countFuture = allPageContentsFuture.thenApply(pageContents -> {
     return pageContents.stream()
            .filter(pageContent -> pageContent.contains("CompletableFuture"))
            .count();
    });
    
    System.out.println("Number of Web Pages having CompletableFuture keyword - " + 
        countFuture.get());
    
    宰父焕
    2023-03-14

    或者,也许您可以从不同的角度处理这个问题,而不是强制使用CompletableFuture,您可以使用CompletionService。

    CompletionService的整体思想是,一旦给定未来的答案准备就绪,它就会被放入一个队列中,您可以从中使用结果。

    备选方案1:没有可完成的未来

    CompletionService<String> cs = new ExecutorCompletionService<>(executor);
    
    List<Future<String>> futures = new ArrayList<>();
    
    futures.add(cs.submit(() -> "One"));
    futures.add(cs.submit(() -> "Two"));
    futures.add(cs.submit(() -> "Three"));
    futures.add(cs.submit(() -> { throw new RuntimeException("Sucks to be four"); }));
    futures.add(cs.submit(() -> "Five"));
    
    
    List<String> successes = new ArrayList<>();
    List<String> failures = new ArrayList<>();
    
    while (futures.size() > 0) {
        Future<String> f = cs.poll();
        if (f != null) {
            futures.remove(f);
            try {
                //at this point the future is guaranteed to be solved
                //so there won't be any blocking here
                String value = f.get();
                successes.add(value);
            } catch (Exception e) {
                failures.add(e.getMessage());
            }
        }
    }
    
    System.out.println(successes); 
    System.out.println(failures);
    

    这将产生:

    [One, Two, Three, Five]
    [java.lang.RuntimeException: Sucks to be four]
    

    备选方案2:具有完全的未来

    但是,如果您真的需要处理CompletableFuture,您也可以将它们提交给完成服务,只需将它们直接放入队列:

    例如,以下变化具有相同的结果:

    BlockingQueue<Future<String>> tasks = new ArrayBlockingQueue<>(5);
    CompletionService<String> cs = new ExecutorCompletionService<>(executor, tasks);
    
    List<Future<String>> futures = new ArrayList<>();
    
    futures.add(CompletableFuture.supplyAsync(() -> "One"));
    futures.add(CompletableFuture.supplyAsync(() -> "Two"));
    futures.add(CompletableFuture.supplyAsync(() -> "Three"));
    futures.add(CompletableFuture.supplyAsync(() -> { throw new RuntimeException("Sucks to be four"); }));
    futures.add(cs.submit(() -> "Five"));
    
    //places all futures in completion service queue
    tasks.addAll(futures);
    
    List<String> successes = new ArrayList<>();
    List<String> failures = new ArrayList<>();
    
    while (futures.size() > 0) {
        Future<String> f = cs.poll();
        if (f != null) {
            futures.remove(f);
            try {
                //at this point the future is guaranteed to be solved
                //so there won't be any blocking here
                String value = f.get();
                successes.add(value);
            } catch (Exception e) {
                failures.add(e.getMessage());
            }
        }
    }
    
    周宏胜
    2023-03-14

    您可以简单地使用allOf()获得一个在所有初始期货都完成(异常或非异常)时完成的期货,然后使用收集器在成功和失败之间分割它们。分区依据()

    List<CompletableFuture<RoomTypes.RoomType>> completableFutures = new ArrayList<>(); //List to hold all the completable futures
    ExecutorService yourOwnExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
    for (Map.Entry<Integer, List> entry : map1.entrySet()) {
        CompletableFuture<RoomTypes.RoomType> requestCompletableFuture = CompletableFuture
                .supplyAsync(
                        () ->
                    //API call which returns object of type RoomTypes.RoomType
                    updateService.updateRoom(51, 33, 759, entry.getKey(),
                            new RoomTypes.RoomType(entry.getKey(), map2.get(entry.getKey()),
                                    entry.getValue())),
                        yourOwnExecutor
                );
    
        completableFutures.add(requestCompletableFuture);
    }
    
    CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
            // avoid throwing an exception in the join() call
            .exceptionally(ex -> null)
            .join();
    Map<Boolean, List<CompletableFuture<RoomTypes.RoomType>>> result =
            completableFutures.stream()
                    .collect(Collectors.partitioningBy(CompletableFuture::isCompletedExceptionally)));
    

    结果映射将包含一个带有true的条目用于失败的期货,另一个带有false键的条目用于成功的期货。然后,您可以检查这两个条目以采取相应的行动。

    请注意,与原始代码相比,有2处轻微更改:

    • 请求完全未来现在是一个完全未来

    关于日志记录/异常处理,只需添加相关的请求复杂uture.handle()来单独记录它们,但保留请求复杂未来,而不是由处理()产生的。

     类似资料:
    • 我正在使用Volley向API发出GET请求: 预期的JSON对象响应很大(可能高达500 KB)。我无法在日志中看到完整的响应。仅显示前50行左右。我还得到了info: BasicNetwork.log慢速请求:请求的HTTP响应= 这意味着请求需要超过3000毫秒。 尝试过的事情: 我已经在手机的开发者选项中将记录器缓冲区大小增加到1M。 原因可能是什么?当它很大的时候,响应是大块发送的吗?如

    • 我想要一个完整的未来,只发出完成的信号(例如,我没有返回值)。 我可以将CompletableFuture实例化为: 但是我应该向完整的方法提供什么呢?例如,我不能做

    • 下面是我的父组件,它包含一个循环的多个输入。如何选择一个来聚焦?在这种情况下,我必须创建动态吗?

    • 我正在创建一个报告,并已经自动化了抓取图像并将其放入的过程。它正在工作,但比它需要的时间要长。我希望有人能帮我实现一个循环来简化代码。 我尝试了几种方法,但当涉及到放置图像的区域时,它似乎总是默认为我设置的初始变量。 DS1=rng&“a.jpg” DS1_1=左(DS1,6)&“00-”&Mid(DS1,4,3)&“99” DS1_2=左(DS1,8) 在错误转到DS3 时,设置shp=acti

    • 有一个名为Avro-Tools的工具,它随Avro一起提供,可以用来在JSON、Avro-Schema(.avsc)和二进制格式之间进行转换。但它不能用于循环引用。 我们有两个文件: > 循环.avsc(由Avro生成) json(由jackson生成,因为它有循环引用,Avro不喜欢这样)。 通告.AVSC circular.json 在上面运行avro-tools的命令 Java-jar av