【问题标题】:Multiple asynchronous HTTP requests using Resttemplate使用 Resttemplate 的多个异步 HTTP 请求
【发布时间】:2019-02-11 21:37:44
【问题描述】:

我有一项服务,它使用弹簧 RestTemplate 调用多个 url。

为了提高性能,我想并行执行这些请求。我有两个选择:

  • 利用 fork-join 公共池的 java 8 个并行流
  • 使用隔离线程池完成未来

只是想知道使用阻塞 I/O 调用的并行流是否是最佳实践?

【问题讨论】:

    标签: java java-8 resttemplate spring-web


    【解决方案1】:

    ForkJoinPool 不适合进行 IO 工作,因为您不会从其工作窃取属性中获得任何好处。如果您打算使用 commonPool 并且您的应用程序的其他部分也这样做,您可能会干扰它们。专用线程池,例如ExecutorService,可能是这两者中更好的解决方案。

    我想提出更好的建议。与其自己编写所有异步包装代码,不如考虑使用 Spring 的AsyncRestTemplate。它包含在 Spring Web 库中,其 API 几乎与 RestTemplate 相同。

    Spring 用于异步客户端 HTTP 访问的中心类。 公开与RestTemplate 类似的方法,但返回ListenableFuture 包装器而不是具体结果。

    [...]

    注意:默认情况下 AsyncRestTemplate 依赖于标准 JDK 工具 建立 HTTP 连接。您可以切换到使用不同的 HTTP 使用 Apache HttpComponents、Netty 和 OkHttp 等库 接受AsyncClientHttpRequestFactory的构造函数。

    ListenableFuture 实例可以通过ListenableFuture::completable() 轻松转换为CompletableFuture 实例。

    如 Javadoc 中所述,您可以通过指定 AsyncClientHttpRequestFactory 来控制要使用的异步机制。对于列出的每个库,都有许多内置实现。在内部,其中一些库可能会按照您的建议执行并在专用线程池上运行阻塞 IO。其他的,比如 Netty(如果有记忆的话),使用非阻塞 IO 来运行连接。您可能会从中获得一些好处。

    然后由您决定如何减少结果。使用CompletableFuture,您可以访问anyOfallOf 帮助器以及任何组合实例方法。

    例如,

    URI exampleURI = URI.create("https://www.stackoverflow.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)。

    【讨论】:

      【解决方案2】:

      Completable future 将是一种更好的方法,因为它在语义上与任务更相关,并且您可以在任务进行时保持代码流继续。

      如果你使用流,除了内部带有异常处理的 lambdas 的笨拙以及它与任务不那么相关的事实之外,在语义上就像在管道中一样,你将不得不等待它们全部完成,即使它们同时发生。为避免这种情况,您将需要期货,但随后您将回到第一个解决方案。

      您可以考虑混合使用,使用流来创建期货。但鉴于它是一组阻塞 IO 请求,您可能没有足够的请求或时间来利用并行流,库可能不会为您并行拆分任务,您最好使用循环.

      【讨论】:

        猜你喜欢
        • 2018-04-10
        • 2023-03-06
        • 2011-01-08
        • 2016-11-15
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 2011-01-09
        相关资源
        最近更新 更多