2008-10-25 18 views
7

मैंने एक बार क्रॉलर को .NET में लिखा था। इसकी स्केलेबिलिटी में सुधार करने के लिए, मैंने .NET के एसिंक्रोनस एपीआई का लाभ उठाने का प्रयास किया।.NET विश्वसनीय Asynchronouos सॉकेट संचार नहीं है?

सिस्टम.Net.HttpWebRequest में एसिंक्रोनस एपीआई BeginGetResponse/EndGetResponse है। हालांकि, एपीआई की यह जोड़ी सिर्फ एक HTTP प्रतिक्रिया शीर्षलेख और एक स्ट्रीम उदाहरण प्राप्त करने के लिए है जिससे हम HTTP प्रतिक्रिया सामग्री निकाल सकते हैं। इसलिए, मेरी रणनीति BeginGetResponse/EndGetResponse को असीमित रूप से प्रतिक्रिया स्ट्रीम प्राप्त करने के लिए उपयोग करना है, फिर प्रतिक्रिया स्ट्रीम उदाहरण से असीमित रूप से बाइट प्राप्त करने के लिए BeginRead/EndRead का उपयोग करें।

क्रॉलर तनाव परीक्षण तक जाने तक सबकुछ सही लगता है। तनाव परीक्षण के तहत, क्रॉलर उच्च स्मृति उपयोग से पीड़ित है। मैंने WinDbg + SoS के साथ मेमोरी की जांच की है और यह बताता है कि कई बाइट एरे सिस्टम द्वारा रेंगते हैं। थ्रेडिंग। ओवरलैप्डडेटा उदाहरण। इंटरनेट में कुछ खोज करने के बाद, मुझे माइक्रोसॉफ्ट से यह KB http://support.microsoft.com/kb/947862 मिला।

केबी के अनुसार, एसिंक्रोनस I/O की संख्या में "ऊपरी सीमा" होनी चाहिए, लेकिन यह "सुझाए गए" बाध्य मान को नहीं बताती है। तो, मेरी आंख में, यह केबी कुछ भी मदद नहीं करता है। यह स्पष्ट रूप से एक .NET बग है। अंत में, मुझे प्रतिक्रिया स्ट्रीम से एसिंक्रोनस निकालने वाले बाइट्स करने के लिए विचार छोड़ना है, और बस इसे तुल्यकालिक तरीके से करें।

नेट पुस्तकालय है कि डॉट नेट सॉकेट साथ अतुल्यकालिक आईओ की अनुमति देता है (Socket.BeginSend/ Socket.BeginReceive/ NetworkStream.BeginRead/ NetworkStream.BeginWrite) की मात्रा पर ऊपरी बाध्य होना आवश्यक है बफर बकाया (या तो भेजें या प्राप्त करें) उनके एसिंक्रोनस आईओ के साथ।

नेटवर्क आवेदन की बकाया अतुल्यकालिक आईओ है कि यह पोस्ट संख्या पर ऊपरी सीमा होनी चाहिए।

संपादित करें: कुछ प्रश्न चिह्न जोड़ें।

किसी को भी सॉकेट & नेटवर्कस्ट्रीम पर एसिंक्रोनस I/O करने का कोई अनुभव है? आम तौर पर, सिंक्रोनस या असिंक्रोनोसली के साथ इंटरनेट के साथ उत्पादन में क्रॉलर I/O करता है?

+0

विषय को छोड़कर एक सिग्नल प्रश्नचिह्न नहीं ... एक बुरा संकेत। –

उत्तर

3

आप स्पष्ट रूप से समवर्ती अनुरोधों की संख्या को सीमित करना चाहते हैं, भले ही आपका क्रॉलर सिंच/एसिंच है। यह सीमा तय नहीं है, यह आपके हार्डवेयर, नेटवर्क पर निर्भर करता है ...

मुझे यकीन नहीं है कि आपका प्रश्न क्या है, क्योंकि HTTP/सॉकेट के .NET कार्यान्वयन "ठीक" है। कुछ छेद हैं (my post देखें टाइमआउट को सही तरीके से नियंत्रित करने के बारे में), लेकिन यह काम पूरा हो जाता है (हमारे पास एक उत्पादन क्रॉलर है जो ~ प्रति सेकंड ~ सैकड़ों पृष्ठों को प्राप्त करता है)।

बीटीडब्ल्यू, हम सुविधा के लिए सिंक्रोनस आईओ का उपयोग करते हैं। प्रत्येक कार्य में धागा होता है, और हम समवर्ती धागे की संख्या को सीमित करते हैं। थ्रेड-प्रबंधन के लिए, हमने Microsoft CCR का उपयोग किया।

+0

मुझे कोई संदेह नहीं है कि सॉकेट पर सिंक्रोनस I/O डॉटनेट में ठीक काम करता है। मैं बस अपने एसिंक्रोनस I/O एपीआई पर भरोसा नहीं करता हूं। –

+0

समस्या ओप को निरस्त/रद्द कर रही है, यह .NET में कभी भी अच्छी तरह से काम नहीं करती है। आपको हमेशा सिंच एपीआई (टाइमआउट के साथ) पसंद करना चाहिए, इस तरह आपको स्वयं को ऑप रद्द करने की आवश्यकता नहीं है। – ripper234

+0

मैं एक कार्य में एक तुल्यकालिक WebRequest लपेटने का भी सुझाव दूंगा। इसके अतिरिक्त थ्रेड का उपयोग न करें, लेकिन कार्य - जो आपको थ्रेडपूल का उपयोग करके व्यापक थ्रेड-जेनरेशन से बचाएगा। यदि आप जोड़कर टास्क कैंसलेशन सोर्स का उपयोग करते हैं, तो आप आसानी से चल रहे कार्य – spookycoder

10

एचएमए, यह एक .NET ढांचा समस्या नहीं है। लिंक किया गया KB आलेख थोड़ा और स्पष्ट हो सकता था: "आप एक भारित बंदूक का उपयोग कर रहे हैं, यह तब होता है जब आप इसे अपने पैर पर लक्षित करते हैं"। उस बंदूक में गोलियां .NET हैं, जो आपको हिम्मत के रूप में कई एसिंक्रोनस I/O अनुरोधों को शुरू करने की क्षमता प्रदान करती हैं। यह तब तक करेगा जो आप इसे करने के लिए कहते हैं, जब तक आप किसी प्रकार की संसाधन सीमा नहीं डालते। इस मामले में, शायद, पीढ़ी 0 ढेर में बहुत अधिक पिन किए गए बफर प्राप्त करते हैं।

संसाधन प्रबंधन अभी भी हमारा काम है, न कि .NET। यह बाध्य किए बिना स्मृति आवंटित करने से अलग नहीं है। इस विशेष समस्या को हल करने के लिए आपको अपूर्ण प्रारंभ GetRetponse() अनुरोधों की संख्या पर सीमा डालना आवश्यक है। उनमें से सैकड़ों को थोड़ा समझ में आता है, उनमें से प्रत्येक को एक समय में इंटरट्यूब के माध्यम से निचोड़ना पड़ता है। एक और अनुरोध जोड़ने से इसे पूरा होने में अधिक समय लगेगा। या अपने कार्यक्रम को दुर्घटनाग्रस्त करें।

+0

को रद्द कर सकते हैं, लेकिन, मैं अपने प्रोग्राम में "ऊपरी बाउंड" कैसे कह सकता हूं? तथ्य यह है कि .NET ने पिनआउट बाइट सरणी जारी नहीं की है, भले ही एप्लिकेशन ने टाइमआउट के बाद BeginXXX ऑपरेशन को निरस्त कर दिया हो। मुझे अभी भी विश्वास है कि यह एक .net बग है। –

+0

नहीं देख सकता कि यह एक सहायक उत्तर कैसे है ?! संसाधनों को जारी करने के लिए –

+1

कॉलिंग एंडएक्स XXXx एक ** हार्ड ** आवश्यकता है। इसे छोड़ो मत। स्पष्ट रूप से जब आप टाइमआउट योजना लागू करते हैं तो दुर्घटना से छोड़ना आसान होता है। –

0

कोई KB आलेख आपको ऊपरी बाउंड नहीं दे सकता है। उपलब्ध हार्डवेयर के आधार पर ऊपरी सीमाएं अलग-अलग हो सकती हैं - 2 जी मेमोरी मशीन के लिए ऊपरी बाउंड 16 जी रैम वाली मशीन के लिए अलग होगी। यह जीसी ढेर के आकार पर भी निर्भर करेगा, यह कितना खंडित है।

आपको क्या करना चाहिए लिफाफे की गणना के पीछे अपने आप के मीट्रिक के साथ आना चाहिए। चित्रित करें कि आप प्रति मिनट कितने पेज डाउनलोड करना चाहते हैं। यह निर्धारित करना चाहिए कि आप कितने एसिंक अनुरोध चाहते हैं (एन)।

एक बार जब आप एन को जानते हैं, तो कोड का एक टुकड़ा बनाएं (जैसे निर्माता-उपभोक्ता पाइपलाइन के उपभोक्ता अंत) जो एन उत्कृष्ट एसिंक डाउनलोड अनुरोध बना सकते हैं। जैसे ही कोई अनुरोध समाप्त हो जाता है (या तो टाइमआउट या सफलता के कारण), कतार से वर्कटाइम खींचकर एक और एसिंक अनुरोध को लात मारो।

आपको यह सुनिश्चित करने की भी आवश्यकता है कि कतार सीमा से परे नहीं बढ़ती है, उदाहरण के लिए, किसी भी कारण से डाउनलोड धीमा हो जाता है।

0

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

3

यह नेट तक सीमित नहीं है।

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

प्रबंधित कोड में यह थोड़ा अधिक जटिल है, जैसा कि आप अप्रबंधित दुनिया में प्राप्त मुद्दों के अतिरिक्त, आपको इस तथ्य से निपटना होगा कि आपके अनुरोधों को पूरा होने तक एसिंक अनुरोधों के लिए उपयोग किए जाने वाले मेमोरी बफर पिन किए गए हैं। लगता है कि आपको इन समस्याओं को पढ़ने के साथ मिल रहा है, लेकिन यह बुरा है, अगर बुरा नहीं है, तो लिखने के लिए (जैसे ही टीसीपी फ्लो कंट्रोल कनेक्शन पर आ जाता है, जैसे ही पूरा करने के लिए पूरा होने लगते हैं और इसलिए उन बफर लंबे और लंबे समय तक पिन किए गए हैं - here और here देखें)।

समस्या यह नहीं है कि .NET async सामग्री टूटा हुआ है, बस इतना ही है कि अमूर्त ऐसा है कि यह वास्तव में यह सब कुछ आसान दिखता है। उदाहरण के लिए, पिनिंग मुद्दे से बचने के लिए, अपने सभी बफर को एक ही, बड़े संगत ब्लॉक में आवंटित करने के बजाय कार्यक्रम शुरू करने के बजाय आवंटित करें ...

व्यक्तिगत रूप से मैं अप्रबंधित कोड में ऐसे क्रॉलर को लिखूंगा, लेकिन यह है बस मुझे;) आप अभी भी कई मुद्दों का सामना करेंगे, लेकिन आप पर थोड़ा अधिक नियंत्रण है।

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