डेटा ओरिएंटेड डिज़ाइन - 1-2 से अधिक संरचना "सदस्यों" के साथ अव्यावहारिक?


23

डेटा ओरिएंटेड डिज़ाइन का सामान्य उदाहरण बॉल संरचना के साथ है:

struct Ball
{
  float Radius;
  float XYZ[3];
};

और फिर वे कुछ एल्गोरिथ्म बनाते हैं जो एक std::vector<Ball>वेक्टर को पुनरावृत्त करते हैं ।

तब वे आपको एक ही चीज़ देते हैं, लेकिन डेटा ओरिएंटेड डिज़ाइन में लागू किया जाता है:

struct Balls
{
  std::vector<float> Radiuses;
  std::vector<XYZ[3]> XYZs;
};

जो अच्छा है और सभी यदि आप पहले सभी त्रिज्याओं को पुनरावृत्त करने जा रहे हैं, तो सभी पदों और इसी तरह। हालांकि, आप वेक्टर में गेंदों को कैसे स्थानांतरित करते हैं? मूल संस्करण में, यदि आपके पास एक है std::vector<Ball> BallsAll, तो आप किसी भी किसी BallsAll[x]को भी स्थानांतरित कर सकते हैं BallsAll[y]

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

डेटा ओरिएंटेड डिज़ाइन के किसी भी प्रदर्शन लाभ को मारना नहीं है?

जवाबों:


23

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

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

हालाँकि, DOD के लिए एक दूसरा पक्ष है। आपको केवल अपने मेमोरी लेआउट को 90 ° मोड़कर और परिणामी संकलित त्रुटियों को ठीक करने के लिए कम से कम सभी कैश और संगठन लाभ नहीं मिलते हैं। इस बैनर के तहत अन्य सामान्य गुर सिखाये जाते हैं। उदाहरण के लिए "अस्तित्व-आधारित प्रसंस्करण": यदि आप बार-बार गेंदों को निष्क्रिय करते हैं और उन्हें फिर से सक्रिय करते हैं, तो गेंद की वस्तु में एक ध्वज न जोड़ें और अपडेट लूप को झूठे सेट किए गए ध्वज के साथ गेंदों को अनदेखा करें। गेंद को "सक्रिय" संग्रह से "निष्क्रिय" संग्रह में ले जाएं, और अपडेट लूप को केवल "सक्रिय" संग्रह का निरीक्षण करें।

अपने उदाहरण के लिए अधिक महत्वपूर्ण और प्रासंगिक रूप से: यदि आप गेंदों की फेरबदल में इतना समय बिताते हैं, तो शायद आप कुछ गलत कर रहे हैं। आदेश क्यों मायने रखता है? क्या आप इसे बना सकते हैं? यदि हां, तो आपको कई लाभ प्राप्त होंगे:

  • आपको संग्रह में फेरबदल करने की आवश्यकता नहीं है (सबसे तेज़ कोड कोई कोड नहीं है)।
  • आप अधिक आसानी से और कुशलता से जोड़ और हटा सकते हैं (अंतिम छोर तक छोड़ें, अंतिम छोड़ें)।
  • शेष कोड आगे अनुकूलन के लिए योग्य हो सकता है (जैसे कि लेआउट परिवर्तन आप जिस पर ध्यान केंद्रित करते हैं)।

इसलिए हर चीज पर आंखें मूंदकर सोआ के बजाय अपने डेटा के बारे में सोचें और आप इसे कैसे प्रोसेस करते हैं। यदि आप पाते हैं कि आप एक लूप में पदों और वेगों को संसाधित करते हैं, तो मेषों के माध्यम से जाएं, और फिर हिट पॉइंट्स को अपडेट करें, अपने मेमोरी लेआउट को इन तीन भागों में विभाजित करने का प्रयास करें। यदि आप पाते हैं कि आप अलगाव में स्थिति के x, y, z घटकों का उपयोग करते हैं, तो शायद अपनी स्थिति वैक्टर को एक SoA में बदल दें। यदि आप अपने आप को वास्तव में उपयोगी कुछ करने से अधिक डेटा फेरबदल पाते हैं, तो शायद इसे फेरबदल करना बंद कर दें।


18

डेटा-ओरिएंटेड माइंडसेट

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

संभवत: जब उपयुक्त हो तो SoA प्रतिनिधि को जन्म दे सकता है:

struct BallSoa
{
   vector<float> x;        // size n
   vector<float> y;        // size n
   vector<float> z;        // size n
   vector<float> r;        // size n
};

... यह अक्सर ऊर्ध्वाधर लूपि लॉजिक के लिए उपयुक्त है जो एक क्षेत्र केंद्र वेक्टर घटकों और त्रिज्या को एक साथ संसाधित नहीं करता है (चार फ़ील्ड एक साथ गर्म नहीं होते हैं), लेकिन एक समय में एक (त्रिज्या के माध्यम से एक लूप, एक और 3 लूप) गोले केंद्रों के व्यक्तिगत घटकों के माध्यम से)।

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

struct BallAoS
{
    float x;
    float y;
    float z;
    float r;
};
vector<BallAoS> balls;        // size n

... अन्य मामलों में यह एक हाइब्रिड का उपयोग करने के लिए उपयुक्त हो सकता है जो दोनों लाभों को संतुलित करता है:

struct BallAoSoA
{
    float x[8];
    float y[8];
    float z[8];
    float r[8];
};
vector<BallAoSoA> balls;      // size n/8

... आप आधी गेंद को कैश लाइन / पृष्ठ में अधिक बॉल फ़ील्ड में फिट करने के लिए आधी-फ्लोट का उपयोग करके गेंद के आकार को आधा कर सकते हैं।

struct BallAoSoA16
{
    Float16 x2[16];
    Float16 y2[16];
    Float16 z2[16];
    Float16 r2[16];
};
vector<BallAoSoA16> balls;    // size n/16

... शायद यहां तक ​​कि त्रिज्या केंद्र क्षेत्र के रूप में लगभग अक्सर एक्सेस नहीं किया जाता है (शायद आपका कोडबेस अक्सर उन्हें बिंदुओं की तरह व्यवहार करता है और केवल शायद ही कभी क्षेत्र के रूप में, उदाहरण के लिए)। उस स्थिति में, आप आगे एक गर्म / ठंडे क्षेत्र की बंटवारे की तकनीक लागू कर सकते हैं।

struct BallAoSoA16Hot
{
    Float16 x2[16];
    Float16 y2[16];
    Float16 z2[16];
};
vector<BallAoSoA16Hot> balls;     // size n/16: hot fields
vector<Float16> ball_radiuses;    // size n: cold fields

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

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

समय से पहले अनुकूलन

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

फिर भी शायद डेटा-उन्मुख डिज़ाइन से लेने के लिए एक मजबूत संदेश ऐसी आशाओं के लिए जगह छोड़ना है। डेटा-उन्मुख मानसिकता को अनुमति देने में मदद मिल सकती है:

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

दानेदार वस्तु-उन्मुख डिजाइन

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

ऑब्जेक्ट-ओरिएंटेड डिज़ाइन के साथ कठिनाई यह है कि यह अक्सर हमें बहुत दानेदार स्तर पर मॉडल इंटरफेस के लिए लुभाता है, जिससे हमें एक समानांतर थोक मानसिकता के बजाय एक स्केलर, एक-एक-समय मानसिकता के साथ फंस जाता है।

एक अतिरंजित उदाहरण के रूप में, एक छवि के एकल पिक्सेल पर लागू ऑब्जेक्ट-उन्मुख डिज़ाइन मानसिकता की कल्पना करें।

class Pixel
{
public:
    // Pixel operations to blend, multiply, add, blur, etc.

private:
    Image* image;          // back pointer to access adjacent pixels
    unsigned char rgba[4];
};

उम्मीद है कि कोई भी वास्तव में ऐसा नहीं करता है। उदाहरण को वास्तव में सकल बनाने के लिए, मैंने पिक्सेल से युक्त बैक पॉइंटर को संग्रहीत किया, ताकि वह धुंधला जैसे छवि प्रसंस्करण एल्गोरिदम के लिए पड़ोसी पिक्सेल तक पहुंच सके।

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

अब एक सी ++ संदर्भ में इस बैक पॉइंटर के अलावा तत्काल ओवरहेड अर्थ में एक वर्ग के साथ कुछ भी गलत नहीं है। C ++ कंपाइलर का ऑप्टिमाइज़ करना हमारे द्वारा बनाई गई सभी संरचना को लेने और इसे स्मिथेरेंस तक सीमित करने में बहुत अच्छा है।

यहाँ कठिनाई यह है कि हम एक पिक्सेल स्तर के दानेदार पर एक संक्षिप्त इंटरफ़ेस मॉडलिंग कर रहे हैं। यह हमें इस प्रकार के दानेदार डिजाइन और डेटा के साथ फंसा देता है, संभावित रूप से बड़ी संख्या में ग्राहक निर्भरताएं उन्हें इस Pixelइंटरफ़ेस के लिए युग्मित करती हैं ।

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

थोक छवि स्तर पर मॉडलिंग करके, हमारे पास अनुकूलन करने के लिए काफी अधिक जगह है। उदाहरण के लिए, हम 16x16 पिक्सेल की तराशी हुई टाइलों के रूप में बड़ी छवियों का प्रतिनिधित्व कर सकते हैं जो 64-बाइट कैश लाइन में पूरी तरह से फिट होती हैं, लेकिन आम तौर पर छोटी स्ट्राइड के साथ पिक्सेल के कुशल पड़ोसी ऊर्ध्वाधर पहुंच की अनुमति देते हैं (यदि हमारे पास कई छवि प्रसंस्करण एल्गोरिदम हैं जो कि) एक कट्टरपंथी डेटा उन्मुख उदाहरण के रूप में एक ऊर्ध्वाधर फैशन में पड़ोसी पिक्सल का उपयोग करने की आवश्यकता है।

एक मोटे स्तर पर डिजाइनिंग

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

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

डेटा-उन्मुख डिज़ाइन अक्सर थोक में मॉडलिंग डेटा एकत्र करने के लिए डेटा को मजबूत करने के विचार से शुरू होता है। एक समान मानसिकता इंटरफ़ेस डिज़ाइन के साथ गूँजती है जो इसके साथ होती है।

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

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


5

आपने जो वर्णन किया है, वह कार्यान्वयन समस्या है। OO डिजाइन स्पष्ट रूप से कार्यान्वयन से चिंतित नहीं है

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

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

तत्वों का कुशल परिवर्धन / निष्कासन अन्य तकनीकों के साथ किया जा सकता है:

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

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


+1 एओएस संगठन एक अच्छी इकाई-उन्मुख एपीआई के लिए पूरी तरह से संशोधन योग्य है, हालांकि जब तक कि आप छद्म-सूचक के माध्यम से एक सुसंगत इकाई को नकली नहीं करना चाहते, तब तक इसका उपयोग करना ( ball->do_something();बनाम ball_table.do_something(ball)) कुरूप हो जाता है (&ball_table, index)

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

4

संक्षिप्त उत्तर: आप पूरी तरह से सही हैं, और इस तरह के लेख इस बिंदु को पूरी तरह से याद कर रहे हैं।

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

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

अधिकांश वर्तमान OO भाषाएँ वस्तुओं और वर्गों के लिए "Array-of-Structure" मेमोरी लेआउट का उपयोग करती हैं। OO के लाभ प्राप्त करना (जैसे आपके डेटा के लिए सार बनाना, एनकैप्सुलेशन और बुनियादी कार्यों का अधिक स्थानीय दायरा), आमतौर पर इस तरह के मेमोरी लेआउट से जुड़ा होता है। इसलिए जब तक आप उच्च प्रदर्शन कंप्यूटिंग नहीं करते हैं, मैं सोआ को प्राथमिक दृष्टिकोण नहीं मानूंगा।


3
डीओडी का मतलब हमेशा स्ट्रक्चर-ऑफ-अर्रे (SoA) लेआउट से नहीं होता है। यह सामान्य है, क्योंकि यह अक्सर एक्सेस पैटर्न से मेल खाता है, लेकिन जब कोई अन्य लेआउट बेहतर काम करता है, तो हर तरह से इसका उपयोग करें। डीओडी एक अधिक सामान्य (और फ़ज़ियर) है, डेटा बिछाने के लिए एक विशिष्ट तरीके से एक डिज़ाइन प्रतिमान की तरह। इसके अलावा, आपके द्वारा संदर्भित लेख सर्वश्रेष्ठ संसाधन से बहुत दूर है और इसकी खामियां हैं, यह SoA लेआउट का विज्ञापन नहीं करता है । "ए" और "बी" एस को पूरी तरह से Ballएस के रूप में अच्छी तरह से चित्रित किया जा सकता है , साथ ही वे व्यक्तिगत floatएस या vec3एस (जो स्वयं सो-परिवर्तन के अधीन होंगे) हो सकते हैं।

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

@delnan: आपकी टिप्पणी के लिए धन्यवाद, आप शायद सही हैं कि मुझे "DOD" के बजाय "SoA" शब्द का उपयोग करना चाहिए था। मैंने उसी के अनुसार अपना उत्तर संपादित किया।
डॉक ब्राउन

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

और यह github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md जिसका SoA से / AoS से स्वत: रूपांतरण है उदाहरण: reddit.com/r/rust/comments/2n6xqz/… और फिर यह है: समाचार। ycombinator.com/item?id=10235766
जैरी यिर्मयाह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.