繁体   English   中英

CompletableFuture join() 方法中的巨大延迟

[英]Huge delay in CompletableFuture join() method

所以我正在开发一个必须一次进行 20 多个 HTTP 调用的应用程序。 他们每个人都需要 2-3 秒才能得到响应。 一次进行一次这些调用(最多 40 秒)非常慢,因此我尝试通过 CompletableFutures 异步发送它们。 这应该允许我在等待其他人的响应时拨打电话,理论上将总时间减少到 4-5 秒而不是 40 秒。

我做了一个与我在https://www.codepedia.org/ama/how-to-make-parallel-calls-in-java-with-completablefuture-example 上找到的教程非常相似的设置。

import org.codingpedia.example;

import javax.inject.Inject;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class ParallelCallsDemoService {

    @Inject
    RestApiClient restApiClient;

    private ExecutorService es = Executors.newFixedThreadPool(20);

    public List<ToDo> getToDos(List<String> ids){

        List<CompletableFuture<ToDo>> futures =
                ids.stream()
                          .map(id -> getToDoAsync(id))
                          .collect(Collectors.toList());

        List<ToDo> result =
                futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

        return result;
    }


    CompletableFuture<ToDo> getToDoAsync(String id){

        CompletableFuture<ToDo> future = CompletableFuture.supplyAsync(() -> {
            return restApiClient.makeSomeHttpCall(id);
        }, es);

        return future;
    }

}

从各方面来看,它似乎都在工作 - 调用都大致在同一时间发送,并且它们都在几秒钟内返回。 但是后来我在这部分遇到了 30-40 秒的巨大延迟:

        List<ToDo> result =
                futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

这使得它与串行发送的时间大致相同,这让我感到困惑。 我怎么会在几秒钟内收到所有回复,但加入他们后会有 30 秒的延迟? 就好像(尽管出现)它们仍然是连续制作的。 为什么加入需要这么长时间?

这里有点问题

List<ToDo> result =
                futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

我认为您使用的流不是并行流。 因此,对 map 的每次调用都在等待最后一次调用完成。 futures.stream()更改为futures.parallelStream()应该会有改进。 当然,如果您使用的不是单核机器。

终于想通了! 谢谢大家的建议。 结果证明这与我对 CompletableFutures 的实现无关。 当我收到来自服务的响应时,我使用 JAXB 将 java 对象转换为 XML 字符串以进行记录。 我在线程挂起时开始查看线程转储,并意识到它实际上是线程正在等待的 JAXB 字符串转换(响应对象非常大)。 我取出那部分,性能立即提高到应有的水平。

我们遇到了类似的问题。 我们已经使用 CompletableFuture 的 '.get(timeout)' 方法解决了它。

CompletableFuture[] array = (CompletableFuture[]) futures.toArray();
       try {
        CompletableFuture.allOf(array).get(180, TimeUnit.SECONDS);
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        //log error
    }

根据您的实时结果设置超时。 您可以使用外部配置调整时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM