[英]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.