春天RestTemplate - 异步VS同步restTemplate [英] Spring RestTemplate - async vs sync restTemplate

查看:5839
本文介绍了春天RestTemplate - 异步VS同步restTemplate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了下面code测试两个同步RestTemplate和AsyncRestTemplate的性能。我只是跑了几次邮差上手动。

I wrote the following code to test the performance of both the sync RestTemplate and AsyncRestTemplate. I just ran it a few times manually on POSTMAN.

我们只是过客10引用到一个GET调用,这样我们可以返回10个链接:

We are just passing 10 references into a GET call so that we can return 10 links:

RestTemplate - 同步和回报2806ms:

ArrayList<String> references = new ArrayList<>();
ArrayList<String> links = new ArrayList<>();
RestTemplate restTemplate = new RestTemplate(); 
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
for (int i = 0; i < 10; i++) {
    ResponseEntity<String> resource = restTemplate.getForEntity(references.get(i), String.class);
    links.add(resource.getBody().toString());
}

RestTemplate - 异步和回报2794ms:

//Creating a synchronizedList so that when the async resttemplate returns, there will be no concurrency issues
List<String> links = Collections.synchronizedList(new ArrayList<String>());

//CustomClientHttpRequestFactory just extends SimpleClientHttpRequestFactory but disables automatic redirects in SimpleClientHttpRequestFactory
CustomClientHttpRequestFactory customClientHttpRequestFactory = new CustomClientHttpRequestFactory();
//Setting the ThreadPoolTaskExecutor for the Async calls
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor pool = new org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor();
pool.setCorePoolSize(5);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
pool.initialize();
//Setting the TaskExecutor to the ThreadPoolTaskExecutor
customClientHttpRequestFactory.setTaskExecutor(pool);

ArrayList<String> references = new ArrayList<>();
ArrayList<String> links = new ArrayList<>();
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(customClientHttpRequestFactory); 
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
for (int i = 0; i < 10; i++) {
    Future<ResponseEntity<String>> resource = asyncRestTemplate.getForEntity(references.get(i), String.class);
    ResponseEntity<String> entity = resource.get(); //this should start up 10 threads to get the links asynchronously
    links.add(entity.getBody().toString());
}

在大多数情况下,这两种方法实际上返回回结果具有非常类似的时间,平均在两个异步和同步呼叫2800ms

In most cases, both methods actually return back the results with a very similar time, averaging 2800ms in both async and sync calls.

我做得不正确的,我本来期望的异步调用要快很多?

Am I doing something incorrect as I would have expected the async call to be much faster?

推荐答案

与Java 未来棘手的事情是,它不是组合的,它真的很容易阻塞。

The tricky thing with Java Future is that it's not composable and it's really easy to block.

在此情况下,调用的Future.get()让你的code座,等待响应回来。事实上,这种方法使得连续通话和没有利用这种异步性质 RestTemplate 实施

In this case, calling future.get() makes your code block and wait until the response is back. In fact, this approach makes sequential calls and does not leverage the async nature of this RestTemplate implementation.

解决这个问题的最简单的方法是将它在两个回路分开:

The simplest way to fix this is to separate it in two loops:

ArrayList<Future<ResponseEntity<String>>> futures = new ArrayList<>();

for (String url : references.get()) {
    futures.add(asyncRestTemplate.getForEntity(url, String.class)); //start up to 10 requests in parallel, depending on your pool
}

for (Future<ResponseEntity<String>> future : futures) {
    ResponseEntity<String> entity = future.get(); // blocking on the first request
    links.add(entity.getBody().toString());
}

显然还有更优雅的解决方案,尤其是在使用JDK8流,lambda表达式和ListenableFuture / CompletableFuture或组成的库。

Obviously there are more elegant solutions, especially if using JDK8 streams, lambdas and ListenableFuture/CompletableFuture or composition libraries.

这篇关于春天RestTemplate - 异步VS同步restTemplate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆