क्या प्रबंधित भाषाओं में कण पूल का उपयोग करना उचित है?


10

मैं जावा में अपने कण प्रणाली के लिए एक ऑब्जेक्ट पूल को लागू करने जा रहा था, तब मुझे यह विकिपीडिया पर मिला । रीफ़्रेज़ करने के लिए, यह कहता है कि ऑब्जेक्ट पूल जावा और सी # जैसी प्रबंधित भाषाओं में उपयोग करने के लायक नहीं हैं, क्योंकि आवंटन सी + ++ जैसी अप्रबंधित भाषाओं में सैकड़ों की तुलना में सिर्फ दसवां संचालन करते हैं।

लेकिन जैसा कि हम सभी जानते हैं, हर निर्देश से खेल के प्रदर्शन को नुकसान पहुंच सकता है। उदाहरण के लिए, एक पैराग्राफ में ग्राहकों का एक पूल: ग्राहक प्रवेश नहीं करेंगे और बहुत तेजी से पूल से बाहर निकलेंगे। लेकिन कण एक सेकंड में दसियों बार नवीनीकृत हो सकते हैं।

सवाल यह है कि क्या किसी प्रबंधित भाषा में कणों के लिए एक ऑब्जेक्ट पूल (विशेष रूप से, जो मर जाते हैं और तेजी से पुन: प्राप्त होते हैं) का उपयोग करने के लिए इसके लायक है?

जवाबों:


14

हाँ यही है।

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

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

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


+1 लेकिन, आपने यह नहीं समझा कि क्या यह संरचना का उपयोग करते समय सार्थक है: मूल रूप से यह नहीं है (पूलिंग मूल्य प्रकार कुछ भी प्राप्त नहीं करता है) - इसके बजाय आपके पास उन्हें प्रबंधित करने के लिए एक एकल (या संभव सेट) सरणी होनी चाहिए।
जोनाथन डिकिंसन

2
चूंकि मैंने जावा का उपयोग करते हुए ओपी का उल्लेख किया था और मैं उस भाषा में मूल्य प्रकार / संरचना के संचालन से परिचित नहीं हूं।

जावा में कोई संरचना नहीं है, केवल कक्षाएं (हमेशा ढेर पर)।
ब्रेंडन लॉन्ग

1

जावा के लिए यह ऑब्जेक्ट्स को पूल करने के लिए उतना उपयोगी नहीं है * क्योंकि वस्तुओं के लिए पहला जीसी चक्र अभी भी चारों ओर स्मृति में फेरबदल करेगा, जिससे उन्हें "ईडन" अंतरिक्ष से बाहर निकलना और संभवतः प्रक्रिया में स्थानिक स्थान खोना होगा।

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

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

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

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

class Particle
{
    public float x;
    public float y;
    public boolean alive;
}

कुछ ऐसा करें:

class Particles
{
    // X positions of all particles. Resize on demand using
    // 'java.util.Arrays.copyOf'. We do not use an ArrayList
    // since we want to work directly with contiguously arranged
    // primitive types for optimal memory access patterns instead 
    // of objects managed by GC.
    public float x[];

    // Y positions of all particles.
    public float y[];

    // Alive/dead status of all particles.
    public bool alive[];
}

मौजूदा कणों के लिए मेमोरी का पुन: उपयोग करने के लिए, आप यह कर सकते हैं:

class Particles
{
    // X positions of all particles.
    public float x[];

    // Y positions of all particles.
    public float y[];

    // Alive/dead status of all particles.
    public bool alive[];

    // Next free position of all particles.
    public int next_free[];

    // Index to first free particle available to reclaim
    // for insertion. A value of -1 means the list is empty.
    public int first_free;
}

अब जब द nth कण मर जाता है, तो इसे पुन: उपयोग करने की अनुमति देने के लिए, इसे इस तरह मुक्त सूची में धकेलें:

alive[n] = false;
next_free[n] = first_free;
first_free = n;

एक नया कण जोड़ते समय, देखें कि क्या आप मुक्त सूची से एक सूचकांक पॉप कर सकते हैं:

if (first_free != -1)
{
     int index = first_free;

     // Pop the particle from the free list.
     first_free = next_free[first_free];

     // Overwrite the particle data:
     x[index] = px;
     y[index] = py;
     alive[index] = true;
     next_free[index] = -1;
}
else
{
     // If there are no particles in the free list
     // to overwrite, add new particle data to the arrays,
     // resizing them if needed.
}

यह काम करने के लिए सबसे सुखद कोड नहीं है, लेकिन इसके साथ आपको अनुक्रमिक कण प्रसंस्करण के साथ कुछ बहुत तेज़ कण सिमुलेशन प्राप्त करने में सक्षम होना चाहिए क्योंकि सभी कण डेटा हमेशा संचित रूप से संग्रहीत किए जाएंगे। इस प्रकार का SoA प्रतिनिधि भी मेमोरी उपयोग को कम करता है क्योंकि हमें पैडिंग, प्रतिबिंब / गतिशील प्रेषण के लिए ऑब्जेक्ट मेटाडेटा के बारे में चिंता करने की आवश्यकता नहीं है, और यह ठंडे क्षेत्रों से दूर गर्म क्षेत्रों को विभाजित करता है (उदाहरण के लिए, हम जरूरी डेटा से चिंतित नहीं हैं भौतिकी के दौरान एक कण के रंग जैसे क्षेत्र पास हो जाते हैं, इसलिए इसे केवल उपयोग न करने और निकालने के लिए इसे कैश लाइन में लोड करना बेकार होगा)।

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

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


1
यह मामले पर एक अच्छा लेखन है, और जावा कोडिंग के 5 साल बाद मैं इसे स्पष्ट रूप से देख सकता हूं; जावा जीसी निश्चित रूप से गूंगा नहीं है, न ही यह गेम प्रोग्रामिंग के लिए बनाया गया था (क्योंकि यह वास्तव में डेटा इलाके और सामान की देखभाल नहीं करता है), इसलिए हम बेहतर खेलते हैं क्योंकि यह प्रसन्न होता है: पी
गुस्तावो मैकिएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.