Java 11 HttpClient - HttpClient 与并发 HttpRequest 的最佳比率是多少

Java 11 HttpClient - What is Optimum Ratio of HttpClients to Concurrent HttpRequests

在下面的示例中,我创建了一个 Java 11 httpClient,然后创建了多个并发 HttpRequest。

  1. 这是不好的做法吗?
  2. 每个 HttpRequest 都应该有自己的 HttpClient 吗?
  3. HttpClient 可以拥有的 HttpRequest 数量是否有上限?

代码

    private static void httpClientExample(){
    
    HttpClient httpClient = HttpClient.newHttpClient();

    System.out.println("TP1");

    var task1 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://www.bing.com/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);

    var task2 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://openjdk.java.net/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);
    
    var task3 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://www.google.co.uk/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);


    System.out.println("Requests Sent");

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("Main Thread Completed");
    }

这在 API docs of HttpClient. But it would be expected that an HttpClient is designed to handle multiple requests. This is in a sense implied on Introduction to the Java HTTP Client 中没有明确记录:

Once built, an HttpClient can be used to send multiple requests.

现在,您的问题可能与管理客户端的并发性有关。这与使用 HttpClient 的相同实例不同,这与它使用的执行程序服务有很大关系,这是您可以自定义的(请参阅 here):

ExecutorService executorService = Executors.newFixedThreadPool(10);
HttpClient httpClient  = HttpClient.newBuilder()
                               .executor(executorService)
                               ... //more config
                               .build();

这样,您可以管理客户端用于 运行 异步请求的线程池。

换句话说:

Is this bad practice?

没有

Should each HttpRequest have its own HttpClient?

没有

Is there an upper limit on the number of HttpRequests a HttpClient can have?

您必须测试应用程序的最佳并发设置,然后使用相应配置的执行程序服务。

我想说的是线程的数量而不是对象的数量,因为每个客户端都可以通过 Executor 的线程池使用许多线程,无论是显式声明的还是默认的。所以真正的问题归结为我们应该使用多少线程? 这将取决于使用同步或异步请求。

  1. 当使用 send 时,我们从池中使用的线程越多,我们能够并行发出的请求就越多,直到 OS 开始 threashing,即增加活动线程的数量实际上会减少完成的工作量。
  2. 在您的示例中使用 sendAsync 时,事情变得很有趣,因为它是 non-blocking 方法,这意味着同一个线程可以在等待处理响应的同时发出多个请求。在这种情况下,我建议将执行程序池中的线程数保持等于处理器内核的数量。