2012-02-26 13 views
63

Techdays यहाँ नीदरलैंड स्टीव सैंडरसन में के दौरान के बारे में C#5, ASP.NET MVC 4, and asynchronous Web.बड़े थ्रेडपूल का उपयोग करने के बजाय एसिंक अनुरोधों का उपयोग क्यों करें?

उन्होंने स्पष्ट किया जब अनुरोध एक लंबे समय के खत्म करने के लिए ले, ThreadPool से सभी धागे बन कि व्यस्त और नए अनुरोधों इंतजार करना एक प्रस्तुति दी। सर्वर लोड को संभाल नहीं सकता है और सब कुछ धीमा हो जाता है।

तब उन्होंने दिखाया कि एसिंक वेबरेक्वेस्ट का उपयोग प्रदर्शन में सुधार कैसे करता है क्योंकि काम को फिर किसी अन्य धागे में सौंप दिया जाता है और थ्रेडपूल नए आने वाले अनुरोधों को तुरंत प्रतिसाद दे सकता है। उन्होंने यह भी दिखाया और दिखाया कि 50 समवर्ती अनुरोधों ने पहले 50 * 1 एस लिया लेकिन कुल मिलाकर एसिंक व्यवहार केवल 1,2 एस में था।

लेकिन यह देखने के बाद भी मेरे पास कुछ प्रश्न हैं।

  1. हम एक बड़े थ्रेडपूल का उपयोग क्यों नहीं कर सकते? एक और धागा धीमा लाने के लिए async/प्रतीक्षा का उपयोग नहीं कर रहा है तो बस शुरुआत से थ्रेडपूल बढ़ रहा है? यह सर्वर की तरह नहीं है जिसे हम अचानक चलाते हैं और अधिक धागे या कुछ मिलता है?

  2. उपयोगकर्ता का अनुरोध अभी भी एसिंक थ्रेड को समाप्त करने का इंतजार कर रहा है। यदि पूल से धागा कुछ और कर रहा है, तो 'यूआई' थ्रेड व्यस्त कैसे रहता है? स्टीव ने 'स्मार्ट कर्नेल' के बारे में कुछ बताया जो कुछ जानता है जब कुछ खत्म हो जाता है '। यह कैसे काम करता है?

उत्तर

55

यह एक बहुत अच्छा सवाल है, और समझना महत्वपूर्ण है कि एसिंक्रोनस आईओ इतना महत्वपूर्ण क्यों है। कारण सी # 5.0 में नई async/प्रतीक्षा सुविधा को जोड़ा गया है कारण लेखन एसिंक्रोनस कोड को सरल बनाना है। सर्वर पर एसिंक्रोनस प्रोसेसिंग के लिए समर्थन नया नहीं है, हालांकि यह एएसपी.नेट 2.0 के बाद से मौजूद है।

स्टीव की तरह आपको सिंक्रोनस प्रोसेसिंग के साथ दिखाया गया है, एएसपी.नेट (और डब्ल्यूसीएफ) में प्रत्येक अनुरोध थ्रेड पूल से एक थ्रेड लेता है। जिस मुद्दे पर उन्होंने प्रदर्शन किया वह एक प्रसिद्ध मुद्दा है जिसे "थ्रेड पूल भुखमरी" कहा जाता है। यदि आप अपने सर्वर पर सिंक्रोनस आईओ बनाते हैं, तो आईओ की अवधि के लिए थ्रेड पूल थ्रेड अवरुद्ध रहेगा (कुछ नहीं कर रहा है)।चूंकि लोड के तहत थ्रेड पूल में धागे की संख्या में एक सीमा है, इसलिए यह ऐसी परिस्थिति में हो सकता है जहां सभी धागे पूल धागे को आईओ के लिए इंतजार कर रहे हैं, और अनुरोध कतार में शुरू होने लगते हैं, जिससे प्रतिक्रिया समय में वृद्धि होती है। चूंकि सभी धागे एक आईओ को पूरा करने की प्रतीक्षा कर रहे हैं, इसलिए आप एक सीपीयू व्यवसाय 0% के करीब देखेंगे (भले ही प्रतिक्रिया समय छत के माध्यम से जाएं)।

आप क्या पूछ रहे हैं (हम एक बड़े थ्रेडपूल का उपयोग क्यों नहीं कर सकते?) एक बहुत अच्छा सवाल है। वास्तव में, इस प्रकार अधिकांश लोग थ्रेड पूल भुखमरी की समस्या को हल कर रहे हैं: अभी थ्रेड पूल पर अधिक धागे हैं। माइक्रोसॉफ्ट के कुछ दस्तावेज यह भी इंगित करते हैं कि थ्रेड पूल भुखमरी होने पर स्थितियों के लिए एक फिक्स के रूप में। यह एक स्वीकार्य समाधान है, और सी # 5.0 तक, यह करना बहुत आसान था, अपने कोड को पूरी तरह से असीमित होने के लिए पुनः लिखने से।

वहाँ दृष्टिकोण के साथ कुछ समस्याएं हालांकि इस प्रकार हैं:

  • कोई मूल्य है कि सभी परिस्थितियों में काम करता है: थ्रेड पूल धागे आप की जरूरत करने जा रहे हैं की संख्या रैखिक की अवधि पर निर्भर करता है आईओ, और आपके सर्वर पर लोड। दुर्भाग्य से, आईओ विलंबता ज्यादातर अप्रत्याशित है। यहां एक उदाहरण है: मान लीजिए कि आप अपने एएसपी.NET एप्लिकेशन में किसी तृतीय पक्ष वेब सेवा पर HTTP अनुरोध करते हैं, जो पूर्ण होने में लगभग 2 सेकंड लगते हैं। आपको थ्रेड पूल भुखमरी का सामना करना पड़ता है, इसलिए आप थ्रेड पूल आकार को बढ़ाने का फैसला करते हैं, मान लें, 200 धागे, और फिर यह फिर से ठीक काम करना शुरू कर देता है। समस्या यह है कि शायद अगले हफ्ते, वेब सेवा में तकनीकी समस्याएं होंगी जो उनके प्रतिक्रिया समय को 10 सेकंड तक बढ़ा देती हैं। अचानक, थ्रेड पूल भुखमरी वापस आ गई है, क्योंकि थ्रेड 5 गुना अधिक अवरुद्ध हैं, इसलिए अब आपको संख्या 5 गुणा, 1,000 धागे तक बढ़ाने की जरूरत है।

  • स्केलेबिलिटी और प्रदर्शन: दूसरी समस्या यह है कि यदि आप ऐसा करते हैं, तो भी आप प्रति अनुरोध एक थ्रेड का उपयोग करेंगे। धागे एक महंगे संसाधन हैं। .NET में प्रत्येक प्रबंधित थ्रेड को स्टैक के लिए 1 एमबी की मेमोरी आवंटन की आवश्यकता होती है। पिछले 5 सेकंड में आईओ बनाने वाले वेबपेज के लिए, और प्रति सेकंड 500 अनुरोधों के भार के साथ, आपको अपने थ्रेड पूल में 2,500 धागे की आवश्यकता होगी, जिसका अर्थ है थ्रेड के ढेर के लिए 2.5 जीबी मेमोरी जो कुछ भी नहीं कर पाएगी। फिर आपके पास संदर्भ स्विचिंग का मुद्दा है, जो आपकी मशीन के प्रदर्शन पर भारी टोल लेगा (मशीन पर सभी सेवाओं को प्रभावित करेगा, न केवल आपके वेब एप्लिकेशन)। भले ही विंडोज प्रतीक्षा थ्रेड को अनदेखा करने में काफी अच्छा काम करता है, लेकिन यह इतनी बड़ी संख्या में धागे को संभालने के लिए डिज़ाइन नहीं किया गया है। याद रखें कि उच्चतम दक्षता प्राप्त की जाती है जब थ्रेड की संख्या मशीन पर लॉजिकल सीपीयू की संख्या के बराबर होती है (आमतौर पर 16 से अधिक नहीं)।

तो थ्रेड पूल के आकार में वृद्धि एक समाधान है, और लोगों को एक दशक (माइक्रोसॉफ्ट के स्वयं के उत्पादों में भी) के लिए है कि कर रहे हैं, यह सिर्फ कम स्केलेबल और कुशल है, स्मृति और CPU के मामले में उपयोग, और आप हमेशा आईओ विलंबता की अचानक वृद्धि की दया पर हैं जो भुखमरी का कारण बनता है। सी # 5.0 तक, असीमित कोड की जटिलता कई लोगों के लिए परेशानी के लायक नहीं थी। async/प्रतीक्षा अब सबकुछ बदलता है, आप एसिंक्रोनस आईओ की स्केलेबिलिटी से लाभ उठा सकते हैं, और एक ही समय में सरल कोड लिख सकते हैं।

अधिक विवरण:। वेब सेवाओं या दूरस्थ वस्तुओं को उत्पन्न करने के लिए अतिरिक्त समानांतर प्रसंस्करण प्रदर्शन करने के लिए, जबकि वेब सेवा कॉल प्राप्त आय जहां संभव हो, तुल्यकालिक (अवरुद्ध) से बचने के लिए एक अवसर है जब वहाँ http://msdn.microsoft.com/en-us/library/ff647787.aspx "अतुल्यकालिक कॉल उपयोग वेब सेवाओं के लिए कॉल क्योंकि आउटगोइंग वेब सेवा कॉल एएसपी.नेट थ्रेड पूल से धागे का उपयोग करके बनाई जाती हैं। कॉलिंग कॉल अन्य आने वाले अनुरोधों को संसाधित करने के लिए उपलब्ध धागे की संख्या को कम करते हैं। "

+14

यह उत्तर प्रश्न के दूसरे भाग का उत्तर नहीं देता है। – nunespascal

+1

एसिंक पैटर्न पर जाने के लिए अच्छा तर्कसंगत। – eduncan911

+3

मुझे नहीं लगता कि यह इस तथ्य को संबोधित करता है कि I/O अप्रत्याशित होने के बावजूद और जो कुछ भी निर्धारित किया गया है, उपयोगकर्ता को अभी भी प्रतिक्रिया प्राप्त करने से पहले सबकुछ करने की प्रतीक्षा करनी है। तथ्य यह है कि http/Web सर्वर स्वयं अधिक भार संभाल सकता है इसका मतलब यह नहीं है कि यह अनुरोध को पूरी तरह से संसाधित करने में सक्षम है। मैं नहीं देखता कि एसिंक इस बात को बदलने के अलावा कैसे हल करता है कि चीज़ों को कैसे वितरित किया जाता है और संभावित रूप से अधिक महंगा संदर्भ स्विचिंग शुरू किया जाता है। – nilskp

29
  1. Async/इंतजार धागे पर आधारित नहीं है; यह एसिंक्रोनस प्रोसेसिंग पर आधारित है। जब आप ASP.NET में एसिंक्रोनस प्रतीक्षा करते हैं, तो अनुरोध थ्रेड थ्रेड पूल में वापस कर दिया जाता है, इसलिए नहीं थ्रेड्स उस अनुरोध को सर्विस करते हैं जब तक कि एसिंक ऑपरेशन पूरा नहीं होता है। चूंकि अनुरोध ओवरहेड थ्रेड ओवरहेड से कम है, इसका मतलब है कि async/प्रतीक्षा थ्रेड पूल से बेहतर स्केल कर सकते हैं।
  2. अनुरोध में बकाया एसिंक्रोनस ऑपरेशंस की गिनती है। यह गणना SynchronizationContext के एएसपी.NET कार्यान्वयन द्वारा प्रबंधित की जाती है। आप SynchronizationContext के बारे में my MSDN article में और अधिक पढ़ सकते हैं - इसमें एएसपी.NET के SynchronizationContext काम और कैसे awaitSynchronizationContext का उपयोग करता है। आप async पृष्ठों इस्तेमाल कर सकते हैं, और ईएपी घटकों का उपयोग इस तरह के रूप WebClient (ईवेंट-आधारित अतुल्यकालिक प्रोग्रामिंग अतुल्यकालिक प्रोग्रामिंग SynchronizationContext के आधार पर की एक शैली है) - async/इंतजार से पहले

ASP.NET अतुल्यकालिक प्रसंस्करण संभव था। Async/await भी SynchronizationContext का उपयोग करता है, लेकिन बहुत आसान वाक्यविन्यास है।

+1

यह अभी भी समझने के लिए थोड़ा मुश्किल है लेकिन जानकारी और आपके लेख के लिए धन्यवाद। यह चीजों को थोड़ा सा स्पष्ट करता है :) क्या आप समझा सकते हैं कि एसिंक प्रोसेसिंग और धागे के बीच क्या बड़ा अंतर है? मैंने सोचा कि अगर मैंने प्रतीक्षा के साथ कुछ कोड निष्पादित किया है तो यह एक अलग धागे पर चला जाएगा ताकि वर्तमान धागा पूल में वापस आ सके। –

+2

@WouterdeKort 'async' कोड को असीमित रूप से चलाता है लेकिन एक नया धागा शुरू नहीं करता है, ऐसा लगता है कि यह वर्तमान थ्रेड में कोड निष्पादित कर रहा है लेकिन' सिंक्रनाइज़ेशन कॉन्टेक्स्ट 'एसिंक कोड लाइन और शेष के बीच स्वैप करेगा विधि ... –

+1

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

6

श्रमिकों है कि आप अपने काम करने के लिए कार्यरत हैं का एक सेट के रूप में ThreadPool कल्पना कीजिए। आपका कार्यकर्ताओं के लिए तेजी से cpu निर्देश चलाने के लिए अपनी कोड।

अब अपने काम पर निर्भर रहना होता है एक और धीमी गति से पुरुष के काम, धीमी पुरुष डिस्क या नेटवर्क जा रहा है उदाहरण के लिए, अपने काम को दो भागों, एक हिस्सा से पहले निष्पादित करने के लिए धीमी गति से पुरुष के काम है, और एक हिस्सा है कि ई करने के लिए हो सकता है। धीमे लड़के के काम के बाद xecute

आप अपने कर्मचारियों को अपना काम करने के लिए कैसे सलाह देंगे? क्या आप प्रत्येक कार्यकर्ता से कहेंगे - "यह पहला भाग करें, फिर उस धीमे आदमी को पूरा होने तक प्रतीक्षा करें, और फिर अपना दूसरा भाग करें"? क्या आप अपने कर्मचारियों की संख्या में वृद्धि करेंगे क्योंकि उनमें से सभी उस धीमी लड़के की प्रतीक्षा कर रहे हैं और आप नए ग्राहकों को संतुष्ट करने में सक्षम नहीं हैं? नहीं!

आप इसके बजाय प्रत्येक कार्यकर्ता से पहले भाग करने के लिए कहेंगे और धीमे लड़के से वापस आने के लिए कहें और कतार में एक संदेश छोड़ दें। कतार में किए गए संदेशों को देखने के लिए आप प्रत्येक कार्यकर्ता (या शायद श्रमिकों का समर्पित सबसेट) बताएंगे और काम के दूसरे भाग को करेंगे।

स्मार्ट गिरी आप के लिए ऊपर इशारा करते रहे हैं ऑपरेटिंग सिस्टम धीमा डिस्क और नेटवर्क आईओ पूरा होने के संदेशों के लिए इस तरह के एक कतार बनाए रखने की क्षमता है।

+2

महान स्पष्टीकरण, वास्तव में यह मेरे लिए नाखुश, धन्यवाद! –

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