2015-07-22 13 views
5

मैंने सिंक RestTemplate और AsyncRestTemplate दोनों के प्रदर्शन का परीक्षण करने के लिए निम्न कोड लिखा था। मैंने इसे POSTMAN पर मैन्युअल रूप से कुछ बार चलाया।स्प्रिंग रेस्ट टेम्पलेट - एसिंक बनाम सिंक बाकी टेम्पलेट

हम सिर्फ इसलिए है कि हम 10 लिंक लौट सकते हैं किसी GET कॉल में 10 संदर्भों से गुजर रहे हैं:

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 - अतुल्यकालिक और रिटर्न में 27 9 4 एमएमएस:

//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 औसत।

क्या मैं कुछ गलत कर रहा हूं क्योंकि मुझे एसिंक कॉल बहुत तेज होने की उम्मीद होगी?

उत्तर

4

जावा Future के साथ मुश्किल चीज यह है कि यह संगत नहीं है और यह ब्लॉक करना वास्तव में आसान है।

इस मामले में, future.get() पर कॉल करने से आपका कोड ब्लॉक हो जाता है और प्रतिक्रिया वापस आने तक प्रतीक्षा करें। वास्तव में, यह दृष्टिकोण अनुक्रमिक कॉल करता है और इस RestTemplate कार्यान्वयन की एसिंक प्रकृति का लाभ नहीं उठाता है।

इसे ठीक करने का सबसे सरल तरीका दो छोरों में यह अलग करने के लिए है:

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 धाराओं, lambdas और ListenableFuture/CompletableFuture या रचना पुस्तकालय हैं।

+0

हाय, धन्यवाद। मुझे आश्चर्य है कि जब हम आपके कोड में ResponseEntity इकाई = future.get() कहते हैं, तो क्या यह कोड को अवरुद्ध नहीं करता है ताकि प्रतिक्रिया प्राप्त होने तक लूप आगे नहीं बढ़े? मैं उस समय में मामूली सुधार देख सकता हूं जहां कॉल 2500ms या उससे भी अधिक में आता है लेकिन यह पर्याप्त नहीं है। – Simon

+0

हाँ, future.get() ब्लॉक लेकिन उस बिंदु पर सभी अनुरोध पहले ही भेजे जा चुके हैं। यदि आप जेडीके 8 कॉम्प्लेटेबल फ्यूचर्स या अन्य रचना पुस्तकालय का उपयोग कर सकते हैं, तो आप कुछ और अधिक कुशल हो सकते हैं। इसे मापते समय, ध्यान रखें कि RestTemplate/AsyncRestTemplate बनाने में समय और संसाधन लगते हैं और एक बार किया जाना चाहिए (और आपके टाइमर में गिनना नहीं चाहिए) –

3

मैं कहूंगा कि आप यहां AsyncRest के वास्तविक लाभ खो रहे हैं। आपको जो भी अनुरोध भेज रहे हैं, उन्हें कॉलबैक जोड़ना चाहिए ताकि प्रतिक्रिया केवल तभी उपलब्ध हो सके जब प्रतिक्रिया उपलब्ध हो।

वास्तव में, AsyncRestTemplate की getForEntity विधि एक सुनवाई योग्य भविष्य देता है जिस पर आप कॉलबैक कार्य कनेक्ट कर सकते हैं। अधिक जानकारी के लिए आधिकारिक दस्तावेज़ ListenableFuture देखें।

अपने मामले में उदाहरण के लिए यह हो सकता है: आपकी प्रतिक्रिया के लिए

for (int i = 0; i < 10; i++) { 
    ListenableFuture<ResponseEntity<String>> response = asyncRestTemplate.getForEntity(references.get(i), String.class); 
    response.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() { 
      @Override 
      public void onSuccess(ResponseEntity<String> result) { 
       // Do stuff onSuccess 
       links.add(result.getBody().toString()); 
      } 

      @Override 
      public void onFailure(Throwable ex) { 
       log.warn("Error detected while submitting a REST request. Exception was {}", ex.getMessage()); 
      } 
     }); 
} 
संबंधित मुद्दे