2013-02-13 13 views
9

मैं अपने जीएई सर्वलेट्स को मल्टीथ्रेड करना चाहता हूं ताकि एक ही उदाहरण पर एक ही सर्वलेट 10 तक संभाल सके (फ्रंटेंड इंस्टेंस I पर विश्वास करें अधिकतम # थ्रेड 10 है) समवर्ती अनुरोध अलग-अलग उपयोगकर्ताओं से एक ही समय में, उनमें से प्रत्येक के बीच समय-निर्धारण।समवर्ती उपयोगकर्ताओं को संभालने के लिए मल्टीथ्रेड GAE servlets

public class MyServlet implements HttpServlet { 
    private Executor executor; 

    @Override 
    public void doGet(HttpServletRequest request, HttpServletResponse response) { 
     if(executor == null) { 
      ThreadFactory threadFactory = ThreadManager.currentRequestFactory(); 
      executor = Executors.newCachedThreadPoolthreadFactory); 
     } 

     MyResult result = executor.submit(new MyTask(request)); 

     writeResponseAndReturn(response, result); 
    } 
} 

तो मूल रूप से जब GAE अप, पहली बार यह इस सर्वलेट के लिए एक अनुरोध हो जाता है शुरू होता है एक Executor बनाई गई है और उसके बाद बचा लिया। फिर प्रत्येक नया सर्वलेट अनुरोध उस निष्पादक का उपयोग करता है जो एक नए धागे को जन्म देता है। जाहिर है MyTask के अंदर सबकुछ थ्रेड-सुरक्षित होना चाहिए।

मुझे इस बारे में चिंता है कि यह वास्तव में ऐसा करता है जो मैं उम्मीद कर रहा हूं। यही है, क्या यह कोड एक गैर-अवरुद्ध सर्वलेट बनाता है जो एक ही समय में एकाधिक उपयोगकर्ताओं से एकाधिक अनुरोधों को संभाल सकता है? यदि नहीं, तो इसे ठीक करने के लिए मुझे और क्यों करने की आवश्यकता है? और, आम तौर पर, क्या कोई और चीज है जो एक जीएई मास्टरो स्पॉट कर सकती है कि वह गलत है? अग्रिम में धन्यवाद।

+0

+1 - मुझे वास्तव में जिस तरह से आप समस्या के बारे में सोच रहे हैं और जिस तरह से आप समाधान के लिए प्रयास करने की कोशिश कर रहे हैं उसे पसंद करते हैं। लेकिन (un-) सौभाग्य से जीएई इस तरह से काम नहीं करता है और 'currentRequestTreadFactory()' विधि काफी कुछ नहीं करती है जो आप इस नाम के आधार पर उम्मीद कर सकते हैं कि आप इसका नाम कैसे पढ़ सकते हैं। मैंने नीचे एक उत्तर पोस्ट किया है जो उम्मीद है कि विधि नाम में अस्पष्टता को साफ़ कर देगा। (यह वर्तमान रिक्वेस्ट-थ्रेड फैक्ट्री है, वर्तमान-अनुरोध थ्रेड-फैक्ट्री नहीं);) –

+0

जिज्ञासा से बाहर: क्या कोई विशिष्ट विशिष्ट है जिसे आप प्राप्त करने की कोशिश कर रहे हैं? मैं पूछ रहा हूं, क्योंकि थोड़ी देर पहले, मैं एक ही प्रश्न में देख रहा था। मैं जीएई का उपयोग करके कुछ प्रकार की लंबी-मतदान पुश अधिसूचनाओं को लागू करने की उम्मीद कर रहा था, लेकिन यह पता चला कि कई अन्य अतिरिक्त मुद्दे हैं जो इस तरह के कुछ तरीके से आपके रास्ते में आ जाएंगे। जीएई वास्तव में उस तरीके को ट्यून करने की अनुमति देने के मामले में काफी सीमित है जिसमें यह शेड्यूल करता है और अनुरोधों को संभालता है। और इनमें से कुछ सीमाएं थोड़ा अस्पष्ट हैं ... लेकिन, ज़ाहिर है, यही कारण है कि यह इतनी तेज़ और मापनीय हो ... –

उत्तर

6

मुझे नहीं लगता कि आपका कोड काम करेगा।

doGet विधि सर्वलेट कंटेनर द्वारा प्रबंधित धागे में चल रही है। जब कोई अनुरोध आता है, तो सर्वलेट थ्रेड पर कब्जा कर लिया जाता है, और इसे doGet विधि वापसी तक जारी नहीं किया जाएगा। आपके कोड में, executor.submitFuture ऑब्जेक्ट लौटाएगा। वास्तविक परिणाम प्राप्त करने के लिए आपको ऑब्जेक्ट पर get विधि का आह्वान करने की आवश्यकता है, और यह तब तक अवरुद्ध होगा जब तक MyTask अपना कार्य पूरा नहीं कर लेता है। केवल उसके बाद, doGet विधि रिटर्न और नए अनुरोधों में किक कर सकते हैं।

मैं GAE से परिचित नहीं हूँ, लेकिन their docs के अनुसार, आप धागे की सुरक्षित के रूप में अपने सर्वलेट घोषणा कर सकते हैं और फिर कंटेनर प्रत्येक वेब को अनेक अनुरोध भेजेंगे समानांतर में सर्वर:

<!-- in appengine-web.xml --> 
<threadsafe>true</threadsafe> 
5

आप परोक्ष दो सवाल पूछा, तो मुझे दोनों का उत्तर दे:

1. मैं अपने AppEngine उदाहरण एकाधिक समवर्ती अनुरोधों को हैंडल करने मिल सकता है?

आप वास्तव में केवल दो काम करने की जरूरत है:

  1. अपने appengine-web.xml फ़ाइल है, जो आप war\WEB-INF फ़ोल्डर में पा सकते हैं करने के लिए बयान <threadsafe>true</threadsafe> जोड़ें।
  2. सुनिश्चित करें कि कोड के अंदर सभी आपके अनुरोध संचालकों वास्तव में धागे की सुरक्षित है, अर्थात अपने doGet(...), doPost(...), आदि तरीकों में केवल स्थानीय चर का उपयोग करें या सुनिश्चित करें कि आप वर्ग या वैश्विक चर के इस्तेमाल के सभी सिंक्रनाइज़ करना सुनिश्चित करें।

यह AppEngine उदाहरण सर्वर रूपरेखा है कि अपने कोड धागा सुरक्षित है बता देंगे और आप इसे अलग धागे में सब आपके अनुरोध संचालकों की कई बार फोन करने के लिए एक ही समय में कई अनुरोधों को हैंडल करने की अनुमति दे रहे हैं। नोट: AFAIK, यह एक प्रति-servlet आधार सेट करना संभव नहीं है। तो, सभी आपके servlets को थ्रेड-सुरक्षित होने की आवश्यकता है!

तो, संक्षेप में, आपके द्वारा पोस्ट किया गया निष्पादक कोड पहले से ही प्रत्येक ऐपइंजिन इंस्टेंस के सर्वर कोड में शामिल है, और वास्तव में आपके doGet(...) विधि को एक अलग थ्रेड के रन विधि के अंदर से कॉल करता है जो AppEngine (या reuses) बनाता है प्रत्येक अनुरोध मूल रूप से doGet() पहले से ही आपके MyTask() है।

डॉक्स के प्रासंगिक भाग यहाँ है (हालांकि यह वास्तव में बहुत ज्यादा नहीं कहना है): https://developers.google.com/appengine/docs/java/config/appconfig#Using_Concurrent_Requests

2. पोस्ट इस के लिए उपयोगी कोड (या किसी अन्य) उद्देश्य है?

अपने वर्तमान रूप में ऐपइंजिन आपको अनुरोधों को स्वीकार करने के लिए अपने स्वयं के धागे बनाने और उपयोग करने की अनुमति नहीं देता है। यह केवल आप के अंदर अपने doGet(...) हैंडलर धागे बनाने के लिए, currentRequestThreadFactory() विधि आप का उल्लेख का उपयोग कर, लेकिन केवल इस एक अनुरोध के लिए समानांतर प्रसंस्करण करते हैं और समानांतर में एक दूसरे से एक को स्वीकार नहीं करने के लिए (यदि ऐसा होता बाहरdoGet()) की अनुमति देता है।

नाम currentRequestThreadFactory() नाम थोड़ा भ्रामक हो सकता है। इसका मतलब यह नहीं है कि यह currentFactoryRequestThreads, यानी अनुरोधों को संभालने वाले थ्रेड लौटाएगा। इसका मतलब है कि यह Factory देता है जो currentRequest के अंदर बना सकता है। इसलिए, दुर्भाग्यवश यह वास्तव में वर्तमान doGet() निष्पादन के दायरे से बाहर लौटे थ्रेड फैक्ट्री का उपयोग करने की अनुमति भी नहीं है, जैसे कि आप इसके आधार पर एक निष्पादक बनाकर और इसे कक्षा चर में रखते हुए सुझाव दे रहे हैं।

फ्रंटेंड उदाहरणों के लिए, doGet() कॉल के अंदर बनाए गए किसी भी थ्रेड को तत्काल समाप्त कर दिया जाएगा जब आपका doGet() विधि रिटर्न होगा। बैकएंड उदाहरणों के लिए, आपको चलने वाले धागे बनाने की अनुमति है, लेकिन चूंकि आपको इन धागे के अंदर अनुरोध स्वीकार करने के लिए सर्वर सॉकेट खोलने की अनुमति नहीं है, फिर भी ये आपको स्वयं को संभालने के अनुरोध को प्रबंधित करने की अनुमति नहीं देंगे।

आप कर सकते हैं और एक ऐप्लिकेशन इंजन सर्वलेट यहाँ के अंदर ऐसा नहीं सकते हैं कि क्या बारे में अधिक जानकारी पा सकते हैं:

The Java Servlet Environment - The Sandbox (विशेष रूप से धागे अनुभाग)

पूर्णता के लिए, आइए देखते हैं आपका कोड "कानूनी" कैसे बनाया जा सकता है:

निम्नलिखित काम करना चाहिए, लेकिन यह आपके कोड के समानांतर में एकाधिक अनुरोधों को संभालने में सक्षम होने के मामले में कोई फर्क नहीं पड़ता है। यह आपको apengine-web.xml में <threadsafe>true</threadsafe> सेटिंग द्वारा पूरी तरह से निर्धारित किया जाएगा। इसलिए, तकनीकी रूप से, यह कोड केवल वास्तव में अक्षम है और दो धागे में एक अनिवार्य रूप से रैखिक कार्यक्रम प्रवाह को विभाजित करता है।लेकिन यहाँ यह वैसे भी है:

public class MyServlet implements HttpServlet { 

    @Override 
    public void doGet(HttpServletRequest request, HttpServletResponse response) { 
     ThreadFactory threadFactory = ThreadManager.currentRequestThreadFactory(); 
     Executor executor = Executors.newCachedThreadPool(threadFactory); 

     Future<MyResult> result = executor.submit(new MyTask(request)); // Fires off request handling in a separate thread 

     writeResponse(response, result.get()); // Waits for thread to complete and builds response. After that, doGet() returns 
    } 
} 

जब से तुम एक अलग थ्रेड उस अनुरोध को आप वर्तमान में संभाल रहे हैं के लिए विशिष्ट है अंदर पहले से ही कर रहे हैं, आप निश्चित रूप से अपने आप को "धागा एक धागा अंदर" बचाने चाहिए और केवल इस के बजाय कार्य करें:

public class MyServlet implements HttpServlet { 

    @Override 
    public void doGet(HttpServletRequest request, HttpServletResponse response) { 
     writeResponse(response, new MyTask(request).call()); // Delegate request handling to MyTask object in current thread and write out returned response 
    } 
} 

या इससे भी बेहतर, कोड को MyTask.call() से doGet() विधि में ले जाएं। -;)

एक तरफ एक साथ 10 सर्वलेट धागे आप का उल्लेख की सीमा के बारे में:

यह एक (अस्थायी) डिजाइन निर्णय है कि और अधिक आसानी से गूगल अपने सर्वर पर लोड को नियंत्रित करने के लिए अनुमति देता है (विशेष रूप से स्मृति है servlets का उपयोग)।

आप यहाँ उन मुद्दों के बारे में अधिक चर्चा पा सकते हैं:

यह विषय भी मुझे से बाहर बिल्ली गुस्सा दिलाना किया गया, के बाद से मैं अल्ट्रा-दुबला सर्वलेट कोड में एक मजबूत आस्तिक हूं, इसलिए समसामयिक अनुरोधों के हजारों नहीं, तो मेरे सामान्य सर्लेट आसानी से सैकड़ों को संभाल सकते हैं। उदाहरण के लिए 10 धागे की इस मनमानी सीमा के कारण अधिक उदाहरणों के लिए भुगतान करना मुझे कम से कम कहने के लिए थोड़ा परेशान है। लेकिन ऊपर दिए गए लिंक पर पढ़ना, ऐसा लगता है जैसे वे इसके बारे में जानते हैं और बेहतर समाधान पर काम कर रहे हैं। तो चलिए देखते हैं कि क्या घोषणाएं गूगल आई/ओ 2013 मई में लाएगा जाने ... :)

2

मैं दूसरे Ericson और मार्कस ए के आकलन

यदि फिर भी, किसी कारण के लिए (या कुछ अन्य परिदृश्य के लिए) आप पथ एक प्रारंभिक बिंदु के रूप में अपने कोड स्निपेट का उपयोग करता है का पालन करना चाहते हैं, मैं सुझाव देंगे कि आप करने के लिए अपने निष्पादक परिभाषा बदलने:

private static Executor executor; 

इतना है कि यह उदाहरणों भर में स्थिर हो जाता है।

संबंधित मुद्दे