जब मेमोरी बैंडविड्थ सीमित संगणनाएं साझा मेमोरी वातावरण में की जाती हैं (जैसे कि ओपनएमपी, थ्रेड्स या टीबीबी के माध्यम से पिरोया गया), तो इस बात की दुविधा है कि यह सुनिश्चित करने के लिए कि मेमोरी को भौतिक मेमोरी में सही तरीके से वितरित किया गया है , जैसे कि प्रत्येक थ्रेड पर स्मृति तक पहुंच होती है। "स्थानीय" मेमोरी बस। हालांकि इंटरफेस पोर्टेबल नहीं हैं, अधिकांश ऑपरेटिंग सिस्टम में थ्रेड एफिनिटी (उदाहरण के लिए pthread_setaffinity_np()
, कई POSIX सिस्टम, sched_setaffinity()
लिनक्स SetThreadAffinityMask()
पर , विंडोज पर) सेट करने के तरीके हैं । मेमोरी पदानुक्रम निर्धारित करने के लिए hwloc जैसी लाइब्रेरी भी हैं , लेकिन दुर्भाग्य से, अधिकांश ऑपरेटिंग सिस्टम अभी तक NUMA मेमोरी पॉलिसी सेट करने के तरीके प्रदान नहीं करते हैं। लिनक्स एक उल्लेखनीय अपवाद है, जिसमें लिबनुमा हैएप्लिकेशन को पेज ग्रैन्युलैरिटी में मेमोरी पॉलिसी और पेज माइग्रेशन में हेरफेर करने की अनुमति देता है (2004 से मेनलाइन में, इस प्रकार व्यापक रूप से उपलब्ध है)। अन्य ऑपरेटिंग सिस्टम उपयोगकर्ताओं से एक अंतर्निहित "पहले स्पर्श" नीति का पालन करने की उम्मीद करते हैं।
"पहले स्पर्श" नीति के साथ काम करने का मतलब है कि कॉल करने वाले को अपनी आत्मीयता के साथ धागे को बनाना और वितरित करना चाहिए, जिसकी वे पहले उपयोग की गई योजना के बाद ताज़ी आवंटित की गई मेमोरी में लिखते हैं। (बहुत कम सिस्टम ऐसे कॉन्फ़िगर किए गए हैं जो malloc()
वास्तव में पृष्ठों को ढूंढते हैं, यह सिर्फ उन्हें खोजने का वादा करता है जब वे वास्तव में दोषपूर्ण होते हैं, शायद अलग-अलग थ्रेड्स द्वारा।) इसका मतलब यह है कि आवंटन का उपयोग calloc()
करने के बाद मेमोरी का उपयोग करना या तुरंत आबंटन करना memset()
हानिकारक है क्योंकि यह गलती की ओर बढ़ेगा। कोर थ्रेड की मेमोरी बस में सभी मेमोरी, जो कि थ्रेडिंग आवंटित की जाती है, सबसे खराब मेमोरी बैंडविड्थ के लिए अग्रणी होती है जब मेमोरी को कई थ्रेड्स से एक्सेस किया जाता है। यही बात C ++ new
ऑपरेटर पर लागू होती है, जो कई नए आवंटन को शुरू करने पर जोर देता है (जैसेstd::complex
)। इस पर्यावरण के बारे में कुछ टिप्पणियां:
- आवंटन को "थ्रेड कलेक्टिव" बनाया जा सकता है, लेकिन अब आवंटन थ्रेडिंग मॉडल में मिश्रित हो जाता है, जो पुस्तकालयों के लिए अवांछनीय है, जो अलग-अलग थ्रेडिंग मॉडल (शायद अपने स्वयं के थ्रेड पूल के साथ) का उपयोग करके ग्राहकों के साथ बातचीत कर सकते हैं।
- RAII को मुहावरेदार C ++ का एक महत्वपूर्ण हिस्सा माना जाता है, लेकिन यह NUM वातावरण में स्मृति प्रदर्शन के लिए सक्रिय रूप से हानिकारक लगता है। प्लेसमेंट
new
का उपयोग मेमोरी सेmalloc()
या रूटीन के माध्यम से आवंटित के साथ किया जा सकता हैlibnuma
, लेकिन यह आवंटन प्रक्रिया को बदलता है (जो मुझे विश्वास है कि आवश्यक है)। - EDIT: ऑपरेटर के बारे में मेरा पहले का बयान
new
गलत था, यह कई तर्कों का समर्थन कर सकता है, चेतन का जवाब देखें। मेरा मानना है कि निर्दिष्ट आत्मीयता का उपयोग करने के लिए पुस्तकालय या एसटीएल कंटेनर प्राप्त करने की चिंता अभी भी है। कई क्षेत्रों को पैक किया जा सकता है और यह सुनिश्चित करने के लिए असुविधाजनक हो सकता है, जैसे,std::vector
सही संदर्भ प्रबंधक सक्रिय के साथ एक reallocates। - प्रत्येक थ्रेड अपनी निजी मेमोरी को आवंटित और दोष कर सकता है, लेकिन फिर पड़ोसी क्षेत्रों में अनुक्रमण अधिक जटिल है। (एक विरल मैट्रिक्स वेक्टर उत्पाद पर विचार करें मैट्रिक्स और वैक्टर की एक पंक्ति विभाजन के साथ; के बिना स्वामित्व वाले भाग का अनुक्रमण एक्स एक और अधिक जटिल डेटा संरचना जब आवश्यकता है एक्स । आभासी स्मृति में सन्निहित नहीं है)
क्या NUMA आवंटन / आरंभीकरण का कोई समाधान मुहावरेदार माना जाता है? क्या मैंने अन्य महत्वपूर्ण गोचरों को छोड़ दिया है?
(मैं अपने सी ++ उदाहरणों के लिए उस भाषा पर जोर देने के लिए उदाहरण नहीं देता हूं, हालांकि सी ++ भाषा स्मृति प्रबंधन के बारे में कुछ फैसले बताती है कि सी जैसी भाषा नहीं होती है, इस प्रकार सी ++ प्रोग्रामर का सुझाव देते समय अधिक प्रतिरोध करने की प्रवृत्ति होती है। चीजें अलग ढंग से।)