我有一个使用springs调用多个urls的服务。
为了提高性能,我想并行地执行这些请求。我有两种选择:
只是想知道是否最好的做法是使用并行流来阻塞I/O调用?
发布于 2019-02-12 02:24:43
ForkJoinPool
对于执行IO工作并不理想,因为您没有从它的工作中获得任何好处--窃取属性。如果您计划使用commonPool
和应用程序的其他部分,您可能会干扰它们。例如,一个专用线程池(例如ExecutorService
)可能是这两个线程池中更好的解决方案。
我想提出更好的建议。与其自己编写所有异步包装代码,不如考虑使用Spring的AsyncRestTemplate
。它包含在Spring库中,它的API几乎与RestTemplate
相同。
Spring用于异步客户端HTTP访问的中心类。公开类似于
RestTemplate
的方法,但返回ListenableFuture
包装器,而不是具体的结果。 ..。 注意:默认情况下,AsyncRestTemplate
依赖于标准的JDK工具来建立HTTP连接。通过使用接受HttpComponents的构造函数,您可以切换到使用不同的HTTP库,如Apache、Netty和OkHttp。
ListenableFuture
实例可以通过ListenableFuture::completable()
轻松地转换为CompletableFuture
实例。
正如在Javadoc中所指出的,您可以通过指定一个AsyncClientHttpRequestFactory
来控制您想要使用的异步机制。对于列出的每个库,都有许多内置的实现。在内部,其中一些库可能会按照您的建议运行阻塞IO在专用线程池上。其他的,如Netty (如果内存服务),使用非阻塞IO来运行连接。你可能会从中受益。
那就看你如何减少结果了。使用CompletableFuture
,您可以访问anyOf
和allOf
助手以及任何组合实例方法。
例如,
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‘WebClient
。这个API有很大的不同,所以我不会深入研究它(除了说它也允许您返回一个CompletableFuture
之外)。
发布于 2019-02-11 23:52:34
可完成的未来将是这样做的更好的方式,因为它在语义上与任务更相关,并且在任务进行时您可能会保持代码流运行。
如果您使用流,除了内部异常处理的lambdas的笨拙性,以及它与任务的语义上不像在管道中那样相关这一事实之外,您还必须等待它们全部完成,即使它们是并行发生的。为了避免这一点,你需要未来,但你会回到第一个解决方案。
您可能会考虑混合,使用流来创建未来。但是,考虑到它是一个阻塞IO请求集,您可能没有足够的请求或时间来利用并行流,库可能不会为您并行地拆分任务,并且您最好使用一个循环。
https://stackoverflow.com/questions/54639538
复制相似问题