使用 Resttemplate 的多个异步 HTTP 请求
Multiple asynchronous HTTP requests using Resttemplate
我有一个使用 springs RestTemplate 调用多个 url 的服务。
为了提高性能,我想并行执行这些请求。我可以使用的两个选项是:
- java 8 个并行流利用 fork-join 公共池
- 使用隔离线程池完成未来
只是想知道使用并行流和阻塞 I/O 调用是否是最佳实践?
Completable future 是更好的方法,因为它在语义上与任务更相关,您可以在任务进行时保持代码流。
如果你使用流,除了内部异常处理的 lambda 的笨拙以及它与任务不太相关的事实之外,在语义上就像在管道中一样,你将不得不等待所有它们完成,即使它们是并行发生的。为避免这种情况,您需要期货,但随后您将回到第一个解决方案。
您可以考虑混合使用流来创建期货。但是考虑到它是一组阻塞的 IO 请求,您可能没有足够的请求或时间来利用并行流,库可能不会为您并行拆分任务,您最好使用循环.
A ForkJoinPool
不适合做 IO 工作,因为你不会从它的工作窃取属性中获得任何好处。如果您计划使用 commonPool
并且您的应用程序的其他部分也这样做,您可能会干扰它们。专用线程池,例如 ExecutorService
,可能是这两者中更好的解决方案。
我想推荐一些更好的。与其自己编写所有异步包装代码,不如考虑使用 Spring 的 AsyncRestTemplate
。它包含在 Spring 网络库中,其 API 几乎与 RestTemplate
相同。
Spring's central class for asynchronous client-side HTTP access.
Exposes similar methods as RestTemplate
, but returns ListenableFuture
wrappers as opposed to concrete results.
[...]
Note: by default AsyncRestTemplate
relies on standard JDK facilities
to establish HTTP connections. You can switch to use a different HTTP
library such as Apache HttpComponents, Netty, and OkHttp by using a
constructor accepting an AsyncClientHttpRequestFactory
.
ListenableFuture
instances can easily be converted to CompletableFuture
instances through ListenableFuture::completable()
.
如 Javadoc 中所述,您可以通过指定 AsyncClientHttpRequestFactory
来控制要使用的异步机制。对于列出的每个库,都有许多内置实现。在内部,其中一些库可能会按照您的建议执行 运行 阻塞专用线程池上的 IO。其他的,比如 Netty(如果没记错的话),使用非阻塞 IO 来 运行 连接。您可能会从中受益。
然后由您决定如何减少结果。使用 CompletableFuture
,您可以访问 anyOf
和 allOf
帮助程序以及任何组合实例方法。
例如,
URI exampleURI = URI.create("https://www.whosebug.com");
AsyncRestTemplate template = new AsyncRestTemplate/* specific request factory*/();
var future1 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future2 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future3 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
CompletableFuture.allOf(future1, future2, future3).thenRun(() -> {
// you're done
});
AsyncRestTemplate
已被弃用,取而代之的是 Spring Web Flux' WebClient
。这个 API 有很大的不同,所以我不会深入研究它(除了说它确实能让你找回 CompletableFuture
)。
我有一个使用 springs RestTemplate 调用多个 url 的服务。
为了提高性能,我想并行执行这些请求。我可以使用的两个选项是:
- java 8 个并行流利用 fork-join 公共池
- 使用隔离线程池完成未来
只是想知道使用并行流和阻塞 I/O 调用是否是最佳实践?
Completable future 是更好的方法,因为它在语义上与任务更相关,您可以在任务进行时保持代码流。
如果你使用流,除了内部异常处理的 lambda 的笨拙以及它与任务不太相关的事实之外,在语义上就像在管道中一样,你将不得不等待所有它们完成,即使它们是并行发生的。为避免这种情况,您需要期货,但随后您将回到第一个解决方案。
您可以考虑混合使用流来创建期货。但是考虑到它是一组阻塞的 IO 请求,您可能没有足够的请求或时间来利用并行流,库可能不会为您并行拆分任务,您最好使用循环.
A ForkJoinPool
不适合做 IO 工作,因为你不会从它的工作窃取属性中获得任何好处。如果您计划使用 commonPool
并且您的应用程序的其他部分也这样做,您可能会干扰它们。专用线程池,例如 ExecutorService
,可能是这两者中更好的解决方案。
我想推荐一些更好的。与其自己编写所有异步包装代码,不如考虑使用 Spring 的 AsyncRestTemplate
。它包含在 Spring 网络库中,其 API 几乎与 RestTemplate
相同。
Spring's central class for asynchronous client-side HTTP access. Exposes similar methods as
RestTemplate
, but returnsListenableFuture
wrappers as opposed to concrete results.[...]
Note: by default
AsyncRestTemplate
relies on standard JDK facilities to establish HTTP connections. You can switch to use a different HTTP library such as Apache HttpComponents, Netty, and OkHttp by using a constructor accepting anAsyncClientHttpRequestFactory
.
ListenableFuture
instances can easily be converted to CompletableFuture
instances through ListenableFuture::completable()
.
如 Javadoc 中所述,您可以通过指定 AsyncClientHttpRequestFactory
来控制要使用的异步机制。对于列出的每个库,都有许多内置实现。在内部,其中一些库可能会按照您的建议执行 运行 阻塞专用线程池上的 IO。其他的,比如 Netty(如果没记错的话),使用非阻塞 IO 来 运行 连接。您可能会从中受益。
然后由您决定如何减少结果。使用 CompletableFuture
,您可以访问 anyOf
和 allOf
帮助程序以及任何组合实例方法。
例如,
URI exampleURI = URI.create("https://www.whosebug.com");
AsyncRestTemplate template = new AsyncRestTemplate/* specific request factory*/();
var future1 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future2 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
var future3 = template.exchange(exampleURI, HttpMethod.GET, null, String.class).completable();
CompletableFuture.allOf(future1, future2, future3).thenRun(() -> {
// you're done
});
AsyncRestTemplate
已被弃用,取而代之的是 Spring Web Flux' WebClient
。这个 API 有很大的不同,所以我不会深入研究它(除了说它确实能让你找回 CompletableFuture
)。