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

1dkrff03  于 2021-07-12  发布在  Java
关注(0)|答案(3)|浏览(718)

因此,我正在开发一个应用程序,它必须一次进行20多个http调用。每一个都需要2-3秒才能得到响应。每次调用一个(最多40秒)相当慢,所以我尝试通过completablefutures异步发送它们。这样我就可以在等待别人回复的时候打电话,理论上可以把总时间从40秒减少到4-5秒。
我做了一个非常类似的设置,我发现在这个教程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秒?这几乎就好像(尽管表面上)它们仍然是连续制作的。为什么加入要花这么长时间?

ljo96ir5

ljo96ir51#

这里有点问题

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

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

nwo49xxi

nwo49xxi2#

终于弄明白了!谢谢大家的建议。原来这跟我实现completablefutures没什么关系。当我从服务接收到响应时,我使用jaxb将java对象转换为xml字符串,以便进行日志记录。我开始研究挂起时的线程转储,并意识到实际上是线程等待的jaxb字符串转换(响应对象相当大)。我去掉了那个部分,表演立刻提高到了应有的水平。

crcmnpdw

crcmnpdw3#

我们也遇到了类似的问题。我们使用completablefuture的“.get(timeout)”方法解决了这个问题。

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

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

相关问题