Ho scritto il seguente codice per testare le prestazioni di sync RestTemplate e AsyncRestTemplate. L'ho eseguito poche volte manualmente su POSTMAN.Spring RestTemplate - async vs sync restTemplate
Siamo solo di passaggio 10 referenze in una chiamata GET in modo da poter tornare 10 collegamenti:
RestTemplate - sincrona e torna a 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 - asincrono e torna a 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());
}
Nella maggior parte dei casi, entrambi i metodi restituiscono effettivamente i risultati con un tempo molto simile, con una media di 2800 ms in entrambe le chiamate asincrone e di sincronizzazione.
Sto facendo qualcosa di sbagliato in quanto mi sarei aspettato che la chiamata asincrona fosse molto più veloce?
Ciao, grazie per la tua risposta. Mi chiedo però quando chiamiamo ResponseEntity entity = future.get() nel tuo codice, non lo blocca anche il codice in modo che il ciclo for non proceda fino a quando la risposta non viene ricevuta? Riesco a vedere un miglioramento marginale nel tempo in cui la chiamata ritorna in 2500ms o giù di lì, ma non è sostanziale. –
Simon
sì, future.get() blocca ma a quel punto tutte le richieste sono già state inviate. Se puoi utilizzare JDK8 CompletableFutures o un'altra libreria di composizione, potresti avere qualcosa di più efficiente. Quando si misura questo, tenere presente che la creazione di un RestTemplate/AsyncRestTemplate richiede tempi e risorse e dovrebbe essere eseguita una sola volta (e non dovrebbe contare nel timer) –