Java 11 HttpClient - HttpClient 与并发 HttpRequest 的最佳比率是多少
Java 11 HttpClient - What is Optimum Ratio of HttpClients to Concurrent HttpRequests
在下面的示例中,我创建了一个 Java 11 httpClient,然后创建了多个并发 HttpRequest。
- 这是不好的做法吗?
- 每个 HttpRequest 都应该有自己的 HttpClient 吗?
- 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 的线程池使用许多线程,无论是显式声明的还是默认的。所以真正的问题归结为我们应该使用多少线程?
这将取决于使用同步或异步请求。
- 当使用
send
时,我们从池中使用的线程越多,我们能够并行发出的请求就越多,直到 OS 开始 threashing,即增加活动线程的数量实际上会减少完成的工作量。
- 在您的示例中使用
sendAsync
时,事情变得很有趣,因为它是 non-blocking 方法,这意味着同一个线程可以在等待处理响应的同时发出多个请求。在这种情况下,我建议将执行程序池中的线程数保持等于处理器内核的数量。
在下面的示例中,我创建了一个 Java 11 httpClient,然后创建了多个并发 HttpRequest。
- 这是不好的做法吗?
- 每个 HttpRequest 都应该有自己的 HttpClient 吗?
- 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 的线程池使用许多线程,无论是显式声明的还是默认的。所以真正的问题归结为我们应该使用多少线程? 这将取决于使用同步或异步请求。
- 当使用
send
时,我们从池中使用的线程越多,我们能够并行发出的请求就越多,直到 OS 开始 threashing,即增加活动线程的数量实际上会减少完成的工作量。 - 在您的示例中使用
sendAsync
时,事情变得很有趣,因为它是 non-blocking 方法,这意味着同一个线程可以在等待处理响应的同时发出多个请求。在这种情况下,我建议将执行程序池中的线程数保持等于处理器内核的数量。