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

问题描述 投票:1回答:2

所以我正在开发一个必须同时进行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秒?几乎(尽管外观)它们仍然是串行制作的。为什么加入需要这么长时间?

java asynchronous completable-future
2个回答
0
投票

这里有些问题

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

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.