2010-08-15 12 views
13

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

मुझे उम्मीद थी कि अस्थायी मामला लगभग रैखिक रूप से स्केल करने की उम्मीद है क्योंकि प्रत्येक धागे को नर्सरी जीन 0 को साफ करना चाहिए और किसी भी साझा संसाधनों के लिए बिना किसी संघर्ष के शुरू करना चाहिए (पुरानी पीढ़ियों तक कुछ भी नहीं बचा है और कोई एल 2 कैश मिस नहीं है क्योंकि जीएन 0 आसानी से एल 1 में फिट बैठता है कैश)।

उदाहरण के लिए, this MSDN article says:

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

क्या कोई मेरी खोजों को सत्यापित कर सकता है और/या मेरी भविष्यवाणियों और अवलोकनों के बीच इस विसंगति को समझा सकता है?

+3

परिभाषित करें कि "कोई स्केलेबिलिटी" से आपका क्या मतलब है। –

+7

आप अपनी सटीक पद्धति को बेहतर तरीके से पोस्ट करते हैं, जो आपने मापा है, आप कैसे मापते हैं और मूल्यों को मापते हैं। –

+2

मैं यहां अनुमान लगा रहा हूं, लेकिन शायद मैं जॉन हैरोप एन-कोर कंप्यूटर पर अपना परीक्षण चला रहा था और एन = 1 से एन धागे के साथ अपना बेंचमार्क कर रहा था। स्केलिंग तब है जब बेंचमार्क की गति एन के साथ बदलती है। –

उत्तर

11

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

+1

"वे फिर भी वैश्विक ढेर का हिस्सा हैं और अलग से एकत्र नहीं किए जा सकते हैं"। यह वही है जो मुझे जानने की जरूरत है। धन्यवाद! –

3

या मेरी भविष्यवाणियों और टिप्पणियों के बीच इस विसंगति को समझाओ?

बेंचमार्किंग कठिन है।
एक उपप्रणाली बेंचमार्किंग जो आपके पूर्ण नियंत्रण में नहीं है, वह भी कठिन है।

12

यह सुनिश्चित नहीं है कि यह आपके मशीन पर क्या देखा गया है और बिल्कुल है। हालांकि आपकी मशीन पर सीएलआर के दो अलग-अलग संस्करण हैं। Mscorwks.dll और mscorsvc.dll। पूर्व वह होता है जब आप अपना प्रोग्राम किसी कार्य स्टेशन पर चलाते हैं, बाद में विंडोज के सर्वर संस्करणों में से एक (जैसे विंडोज 2003 या 2008)।

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

आप अपने वर्कस्टेशन पर सर्वर संस्करण का चयन कर सकते हैं, अपने .config फ़ाइल में <gcServer> तत्व का उपयोग करें।

4

मैं कुछ अनुमानों को खतरे में डाल सकता हूं कि क्या हो रहा है।

(1) यदि आपके पास एक सिंगल थ्रेड है और एम स्पेस पीढ़ी 0 में मुक्त है, तो जीसी केवल एक बार एम बाइट आवंटित किए जाने के बाद ही चलाएगा।

(2) यदि आपके पास एन धागे हैं और जीसी प्रति थ्रेड एन/एम स्पेस में पीढ़ी 0 को विभाजित करता है, तो हर बार थ्रेड एन/एम बाइट आवंटित करने पर जीसी समाप्त हो जाएगा। यहां शोस्टॉपर यह है कि जीसी को थ्रेड के रूट सेट से संदर्भों को चिह्नित करने के लिए "दुनिया को रोकना" (यानी, सभी चल रहे धागे को निलंबित करना) की आवश्यकता होती है। यह सस्ता नहीं है। इसलिए, न केवल जीसी अधिक बार दौड़ेंगे, यह प्रत्येक संग्रह पर अधिक काम करेगा।

दूसरी समस्या, ज़ाहिर है कि बहु-थ्रेडेड अनुप्रयोग आमतौर पर बहुत कैश अनुकूल नहीं होते हैं, जो आपके प्रदर्शन में एक महत्वपूर्ण दांत भी डाल सकते हैं।

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

+0

@ राफ: "जीसी को दुनिया को रोकने की जरूरत है"। क्या आपको यकीन है? मैं ऐसे डिज़ाइनों की कल्पना कर सकता हूं जहां नर्सरी पीढ़ी में ऑब्जेक्ट्स की सभी जड़ें वैश्विक चर में हैं, (एक) थ्रेड-लोकल स्टैक और लिखने वाले बाधा द्वारा उत्पन्न एक याद किया गया सेट। –

+1

@ जोन: यह थोड़ा देर हो चुकी है, इसलिए मैं यहां आधार से बाहर हो सकता हूं, लेकिन प्रत्येक मशीन रजिस्टर को वैश्विक या स्टैक स्लॉट द्वारा समर्थित करने की आवश्यकता नहीं होगी बल्कि कोड जनरेशन अनुकूलन को अस्वीकार कर दिया जाएगा? इसके अलावा, बाधाओं को लिखना सस्ता नहीं होता है। मेरे मन में यह है कि यह है: जीसी के पास यह जानने का कोई तरीका नहीं है कि मैंने थ्रेड जे को स्थानीय ऑब्जेक्ट का संदर्भ नहीं दिया है, इसलिए इसे मेरी नर्सरी में संदर्भ देखने के लिए जम्मू की जड़ों की जांच करने की आवश्यकता है। किसी भी तरह से, "मल्टीथ्रेडेड एप्लिकेशन के लिए प्रदर्शन" के तहत लिंक किए गए आलेख की मेरी पढ़ाई यह थी कि .NET जीसी एक स्टॉप-द-वर्ल्ड टाइप है। – Rafe

+0

@ राफ: "प्रत्येक मशीन रजिस्टर को ग्लोबल या स्टैक स्लॉट द्वारा समर्थित करने की आवश्यकता नहीं होगी बल्कि कोड जनरेशन अनुकूलन को अस्वीकार कर दिया जाएगा"। नहीं, मैंने एचएलवीएम में तकनीक का उपयोग किया और यह बहुत तेज़ कोड उत्पन्न करता है। –

4

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

यह भी सावधान रहें कि डबल पॉइंटर्स के साथ "ढेर" में 2 भाग हैं - स्मृति का ब्लॉक दें और हैंडल-सूचक तालिका (ताकि ब्लॉक को स्थानांतरित किया जा सके लेकिन आपके कोड में हमेशा एक पता हो)। ऐसी तालिका एक महत्वपूर्ण लेकिन बहुत दुबला प्रक्रिया-स्तर संसाधन है और इसे तनाव देने का एकमात्र तरीका भारी त्वरित रिलीज के साथ बाढ़ करना है - इसलिए आप इसे करने में कामयाब रहे :-))

सामान्यतः जीसी के नियम है - लीक :-) बेशक हमेशा के लिए नहीं, लेकिन जब तक आप कर सकते हैं के लिए तरह। अगर आपको याद है कि लोग "जीसी संग्रह को मजबूर नहीं करते" कह रहे हैं? यह कहानी का हिस्सा है। इसके अलावा "दुनिया को रोकें" संग्रह वास्तव में "समवर्ती" से अधिक कुशल है और चक्र चोरी या शेड्यूलर सहयोग के अच्छे नाम से जाना जाता है। केवल मार्क चरण को शेड्यूलर को फ्रीज करने की आवश्यकता होती है और सर्वर पर कई धागे का विस्फोट होता है (एन कोर वैसे भी निष्क्रिय होते हैं :-) दूसरे के लिए एकमात्र कारण यह है कि यह रीयल-टाइम ऑपरेशन कर सकता है जैसे वीडियो बजाना , जैसे लंबे धागे क्वांटम करता है।

तो फिर यदि आप छोटे और लगातार सीपीयू विस्फोट (छोटे आवंटन, लगभग कोई काम नहीं, त्वरित रिलीज) पर बुनियादी ढांचे के साथ प्रतिस्पर्धा करते हैं तो केवल एक चीज जिसे आप देखेंगे/मापेंगे जीसी और जेआईटी शोर होगा।

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

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