簡體   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