Итак, я работаю над приложением, которое должно совершать более 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 секунд? Это почти как если бы (несмотря на внешность) они все еще делались серийно. Почему объединение занимает так много времени?