Data Oriented Design - ทำไม่ได้กับสมาชิกมากกว่า 1-2 โครงสร้าง?


23

ตัวอย่างปกติของ Data Oriented Design ที่มีโครงสร้าง Ball:

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

แล้วพวกเขาก็สร้างอัลกอริทึมที่วนซ้ำstd::vector<Ball>เวกเตอร์

จากนั้นพวกเขาก็ให้สิ่งเดียวกัน แต่นำไปใช้ใน Data Oriented Design:

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

ซึ่งเป็นสิ่งที่ดีและทั้งหมดถ้าคุณจะทำซ้ำรัศมีทั้งหมดก่อนอื่นจากนั้นทุกตำแหน่งและอื่น ๆ อย่างไรก็ตามคุณจะย้ายลูกบอลในเวกเตอร์ได้อย่างไร ในรุ่นเดิมหากคุณมีstd::vector<Ball> BallsAllคุณก็สามารถย้ายใดๆBallsAll[x]BallsAll[y]

อย่างไรก็ตามในการทำเช่นนั้นสำหรับ Data Oriented เวอร์ชั่นคุณต้องทำสิ่งเดียวกันสำหรับทุก ๆ คุณสมบัติ (2 ครั้งในกรณีของ Ball - radius and position) แต่มันจะแย่ลงถ้าคุณมีคุณสมบัติมากขึ้น คุณจะต้องเก็บดัชนีสำหรับ "ลูกบอล" แต่ละลูกและเมื่อคุณพยายามที่จะย้ายไปรอบ ๆ คุณต้องทำการย้ายในทุก ๆ คุณสมบัติของเวกเตอร์

นั่นไม่ได้ทำลายประสิทธิภาพการทำงานของ Data Oriented Design หรือไม่?

คำตอบ:


23

คำตอบอีกข้อหนึ่งให้ภาพรวมที่ยอดเยี่ยมเกี่ยวกับวิธีที่คุณจะแค็ปซูลพื้นที่จัดเก็บข้อมูลแบบแถวและให้มุมมองที่ดีขึ้น แต่เนื่องจากคุณยังถามเกี่ยวกับประสิทธิภาพการทำงานให้ฉันอยู่ที่: รูปแบบ SOA ไม่ใช่ bullet มันเป็นค่าเริ่มต้นที่ค่อนข้างดี (สำหรับการใช้งานแคชไม่มากสำหรับความง่ายในการใช้งานในภาษาส่วนใหญ่) แต่มันไม่ใช่ทั้งหมดที่มีอยู่ไม่ใช่แม้แต่ในการออกแบบเชิงข้อมูล เป็นไปได้ว่าผู้เขียนแนะนำบางอย่างที่คุณอ่านพลาดจุดนั้นและนำเสนอเค้าโครง SoA เท่านั้นเนื่องจากพวกเขาคิดว่านั่นเป็นจุดรวมของ DOD พวกเขาจะผิดและขอบคุณที่ทุกคนไม่ได้ตกหลุมพรางนั้น

อย่างที่คุณอาจรู้อยู่แล้วไม่ใช่ว่าข้อมูลดั้งเดิมทุกชิ้นจะไม่ได้รับประโยชน์จากการถูกดึงออกมาในอาร์เรย์ของมันเอง เลย์เอาต์ SoA นั้นมีข้อดีเมื่อส่วนประกอบที่คุณแบ่งออกเป็นอาร์เรย์แยกต่างหากมักจะเข้าถึงแยกต่างหาก แต่ไม่ใช่ว่าทุก ๆ ชิ้นส่วนเล็ก ๆ จะถูกแยกออกเป็นชิ้น ๆ เช่นเวกเตอร์ตำแหน่งนั้นมักจะอ่านและอัปเดตขายส่งอยู่เสมอดังนั้นโดยปกติคุณจะไม่แยกมันออก อันที่จริงตัวอย่างของคุณก็ไม่ได้ทำเช่นนั้น! ในทำนองเดียวกันถ้าคุณมักจะเข้าถึงคุณสมบัติทั้งหมดของลูกบอลด้วยกันเพราะคุณใช้เวลาส่วนใหญ่ในการแลกเปลี่ยนลูกบอลรอบ ๆ ในคอลเล็กชันลูกบอลของคุณไม่มีจุดแยกใด ๆ

อย่างไรก็ตามยังมีด้านที่สองสำหรับ DOD คุณไม่ได้รับแคชและข้อได้เปรียบขององค์กรทั้งหมดเพียงแค่หมุนเลย์เอาต์หน่วยความจำ 90 °และทำอย่างน้อยที่สุดเพื่อแก้ไขข้อผิดพลาดในการคอมไพล์ มีเทคนิคทั่วไปอื่น ๆ ที่สอนภายใต้แบนเนอร์นี้ ตัวอย่างเช่น "การประมวลผลตามการมีอยู่ของ": ถ้าคุณปิดการใช้งานลูกบอลและเปิดใช้งานอีกครั้งบ่อยครั้งไม่ต้องเพิ่มค่าสถานะลงในวัตถุลูกและทำให้ห่วงการปรับปรุงไม่สนใจลูกด้วยการตั้งค่าธงเป็นเท็จ ย้ายลูกบอลจากคอลเล็กชัน "แอ็คทีฟ" ไปยังคอลเล็กชัน "ไม่แอ็คทีฟ" และทำให้ลูปการอัพเดตตรวจสอบคอลเล็กชัน "แอ็คทีฟ" เท่านั้น

มีความสำคัญและเกี่ยวข้องกับตัวอย่างของคุณมากขึ้น: ถ้าคุณใช้เวลามากในการสลับแถวบอลคุณอาจกำลังทำอะไรผิดพลาด ทำไมการสั่งซื้อถึงมีความสำคัญ? คุณทำให้มันไม่สำคัญหรือไม่ ถ้าเป็นเช่นนั้นคุณจะได้รับประโยชน์หลายอย่าง:

  • คุณไม่จำเป็นต้องสลับคอลเลคชั่น (รหัสที่เร็วที่สุดคือไม่มีรหัสเลย)
  • คุณสามารถเพิ่มและลบได้ง่ายขึ้นและมีประสิทธิภาพ (สลับไปยังจุดสิ้นสุดวางสุดท้าย)
  • รหัสที่เหลืออาจมีสิทธิ์ได้รับการเพิ่มประสิทธิภาพเพิ่มเติม (เช่นการเปลี่ยนเค้าโครงที่คุณมุ่งเน้น)

ดังนั้นแทนที่จะขว้าง SOA ไปที่ทุกอย่างให้นึกถึงข้อมูลของคุณและวิธีการที่คุณประมวลผล หากคุณพบว่าคุณประมวลผลตำแหน่งและความเร็วในการวนรอบหนึ่งวงจากนั้นผ่านตาข่ายและจากนั้นอัปเดต hitpoints ลองแบ่งเลย์เอาต์หน่วยความจำของคุณออกเป็นสามส่วน หากคุณพบว่าคุณเข้าถึงส่วนประกอบ 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 ลูป ผ่านแต่ละองค์ประกอบของศูนย์ทรงกลม)

ในกรณีอื่น ๆ อาจเป็นการเหมาะสมที่จะใช้ AoS หากมีการเข้าถึงฟิลด์ด้วยกันบ่อยครั้ง (ถ้าตรรกะการวนรอบของคุณวนซ้ำทุกสนามของลูกแทนที่จะเป็นรายบุคคล) และ / หรือถ้าต้องการการเข้าถึงแบบสุ่มของลูกบอล:

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

กุญแจสำคัญในการออกแบบที่มุ่งเน้นข้อมูลคือการพิจารณาการเป็นตัวแทนทุกประเภทเหล่านี้ในช่วงต้นของการตัดสินใจออกแบบของคุณเพื่อที่จะไม่ดักจับตัวคุณเองให้เป็นตัวแทนย่อยที่ดีที่สุดด้วยอินเทอร์เฟซสาธารณะที่อยู่ด้านหลัง

มันให้ความสำคัญกับรูปแบบการเข้าถึงหน่วยความจำและรูปแบบประกอบทำให้พวกเขากังวลมากขึ้นกว่าปกติ ในความรู้สึกมันก็อาจจะทำลาย abstractions ฉันพบโดยใช้ความคิดนี้มากกว่าที่ฉันไม่ได้ดูอีกต่อไปstd::dequeเช่นในแง่ของความต้องการอัลกอริทึมของมันค่อนข้างมากเท่ากับการแสดงบล็อกที่ต่อเนื่องกันที่รวบรวมไว้และการเข้าถึงแบบสุ่มของมันทำงานในระดับหน่วยความจำ มันค่อนข้างให้ความสำคัญกับรายละเอียดการใช้งาน แต่รายละเอียดการใช้งานซึ่งมีแนวโน้มที่จะมีผลกระทบต่อประสิทธิภาพเพียงเล็กน้อยหรือมากกว่านั้นตามความซับซ้อนของอัลกอริธึมที่อธิบายการขยายขีดความสามารถ

การเพิ่มประสิทธิภาพก่อนวัยอันควร

จุดสนใจที่เด่นชัดจำนวนมากของการออกแบบที่มุ่งเน้นข้อมูลจะปรากฏขึ้นอย่างน้อยในทันทีที่ใกล้ถึงการปรับให้เหมาะสมก่อนที่จะเกิดอันตราย ประสบการณ์มักสอนเราว่าการเพิ่มประสิทธิภาพขนาดเล็กนั้นถูกนำไปใช้ในการเข้าใจย้อนหลังที่สุดและมีผู้สร้างโปรไฟล์ในมือ

แต่บางทีข้อความที่แข็งแกร่งที่จะรับจากการออกแบบเชิงข้อมูลคือการออกจากพื้นที่สำหรับการเพิ่มประสิทธิภาพดังกล่าว นั่นคือความคิดเชิงข้อมูลที่สามารถช่วยให้:

การออกแบบที่เน้นข้อมูลสามารถออกจากห้องหายใจเพื่อสำรวจการนำเสนอที่มีประสิทธิภาพมากขึ้น ไม่จำเป็นต้องเกี่ยวกับการบรรลุความสมบูรณ์แบบของหน่วยความจำในครั้งเดียว แต่เพิ่มเติมเกี่ยวกับการพิจารณาที่เหมาะสมล่วงหน้าเพื่อให้การเป็นตัวแทนที่ดีที่สุดเพิ่มขึ้น

การออกแบบเชิงวัตถุที่ละเอียด

การอภิปรายเกี่ยวกับการออกแบบเชิงข้อมูลจำนวนมากจะทำให้ตนเองแตกต่างจากแนวคิดดั้งเดิมของการเขียนโปรแกรมเชิงวัตถุ ถึงกระนั้นฉันก็จะเสนอวิธีการดูสิ่งนี้ซึ่งไม่ง่ายนักที่จะยกเลิก OOP ทั้งหมด

ความยากลำบากในการออกแบบเชิงวัตถุคือมันมักจะดึงดูดเราให้ทำโมเดลอินเตอร์เฟสในระดับย่อย ๆ ทำให้เราติดกับ scalar ความคิดแบบครั้งต่อครั้งแทนที่จะเป็นความคิดแบบกลุ่มจำนวนมาก

เป็นตัวอย่างที่พูดเกินจริงลองจินตนาการถึงแนวคิดการออกแบบเชิงวัตถุที่นำไปใช้กับพิกเซลเดียวของภาพ

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 ++ นอกเหนือจากตัวชี้หลังนี้ การเพิ่มประสิทธิภาพคอมไพเลอร์ C ++ นั้นยอดเยี่ยมในการใช้โครงสร้างทั้งหมดที่เราสร้างขึ้นและกำจัดมันให้เป็นโรงหลอมขนาดเล็ก

ความยากของที่นี่คือเรากำลังสร้างโมเดลอินเทอร์เฟซแบบแค็ปซูลที่ระดับพิกเซลเกินไป นั่นทำให้เราติดกับการออกแบบที่ละเอียดและข้อมูลแบบนี้โดยอาจมีการพึ่งพาลูกค้าจำนวนมากที่เชื่อมต่อกับPixelอินเทอร์เฟซนี้

วิธีแก้ปัญหา: กำจัดโครงสร้างเชิงวัตถุของพิกเซลเม็ดเล็กออกและเริ่มสร้างโมเดลอินเทอร์เฟซของคุณที่ระดับ coarser ที่เกี่ยวข้องกับจำนวนพิกเซลจำนวนมาก (ที่ระดับภาพ)

ด้วยการสร้างแบบจำลองที่ระดับรูปภาพจำนวนมากเรามีพื้นที่เพิ่มประสิทธิภาพมากขึ้นอย่างมีนัยสำคัญ ยกตัวอย่างเช่นเราสามารถแสดงภาพขนาดใหญ่เป็นภาพรวมที่มีขนาด 16x16 พิกเซลซึ่งพอดีกับแคชแคชแบบ 64 ไบต์ แต่อนุญาตการเข้าถึงพิกเซลแนวตั้งที่มีประสิทธิภาพซึ่งอยู่ใกล้เคียงกับการก้าวเล็ก ๆ (ถ้าเรามีอัลกอริธึมการประมวลผลภาพจำนวนมาก จำเป็นต้องเข้าถึงพิกเซลข้างเคียงในแนวตั้ง) เป็นตัวอย่างที่ไม่ยอมใครง่ายๆ

การออกแบบในระดับ Coarser

ตัวอย่างข้างต้นของอินเทอร์เฟซการสร้างแบบจำลองที่ระดับรูปภาพเป็นตัวอย่างที่ไม่มีเกมง่ายๆเนื่องจากการประมวลผลภาพเป็นฟิลด์ที่โตเต็มที่ที่ได้รับการศึกษาและปรับให้เหมาะกับความตาย ทว่าสิ่งที่เห็นได้ชัดเจนน้อยกว่านั้นอาจเป็นอนุภาคในตัวปล่อยอนุภาคสไปรท์กับคอลเล็กชั่นสไปรท์ขอบในกราฟของขอบหรือแม้แต่บุคคลกับกลุ่มคน

กุญแจสำคัญในการอนุญาตการปรับให้เหมาะสมที่สุดกับข้อมูล (ในการคาดการณ์ล่วงหน้าหรือการเข้าใจถึงปัญหาหลังเหตุการณ์) มักจะทำให้การออกแบบส่วนต่อประสานลดลง แนวคิดของการออกแบบส่วนต่อประสานสำหรับเอนทิตีเดี่ยวจะถูกแทนที่ด้วยการออกแบบสำหรับคอลเลกชันของเอนทิตีที่มีการดำเนินการขนาดใหญ่ที่ประมวลผลเป็นกลุ่ม เป้าหมายนี้โดยเฉพาะอย่างยิ่งและทันทีเข้าถึงลูปลำดับที่จำเป็นต้องเข้าถึงทุกอย่างและไม่สามารถช่วย แต่มีความซับซ้อนเชิงเส้น

การออกแบบเชิงข้อมูลมักเริ่มต้นด้วยแนวคิดการรวมข้อมูลเพื่อจัดทำแบบจำลองการรวมข้อมูลเป็นกลุ่ม ความคิดที่คล้ายกันสะท้อนไปยังการออกแบบอินเตอร์เฟสที่มาพร้อมกับมัน

นี่เป็นบทเรียนที่มีค่าที่สุดที่ฉันนำมาจากการออกแบบเชิงข้อมูลเนื่องจากฉันไม่เข้าใจสถาปัตยกรรมคอมพิวเตอร์มากพอที่จะค้นหาเลย์เอาต์ของหน่วยความจำที่ดีที่สุดสำหรับบางสิ่งในการลองครั้งแรก มันกลายเป็นสิ่งที่ฉันพูดย้ำด้วย profiler ในมือ (และบางครั้งก็พลาดไปตามทางที่ฉันไม่ได้เร่งความเร็ว) แต่ด้านการออกแบบส่วนต่อประสานของการออกแบบเชิงข้อมูลคือสิ่งที่ทำให้ฉันมีพื้นที่ว่างในการค้นหาการแสดงข้อมูลที่มีประสิทธิภาพมากขึ้น

กุญแจสำคัญคือการออกแบบส่วนต่อประสานในระดับที่หยาบกว่าที่เรามักจะอยากทำ สิ่งนี้มักจะมีประโยชน์ด้านเช่นการลดค่าใช้จ่ายการจัดส่งแบบไดนามิกที่เกี่ยวข้องกับฟังก์ชั่นเสมือนการเรียกตัวชี้ฟังก์ชั่นการเรียก dylib และการไร้ความสามารถสำหรับผู้ที่จะ inline แนวคิดหลักที่จะนำมาใช้ทั้งหมดนี้คือการดูการประมวลผลในแบบกลุ่ม (ถ้ามี)


5

สิ่งที่คุณอธิบายเป็นปัญหาการใช้งาน การออกแบบ OO ไม่ได้เกี่ยวข้องกับการใช้งานอย่างชัดเจน

คุณสามารถแค็ปซูลคอนเทนเนอร์บอลที่เน้นคอลัมน์ด้านหลังอินเทอร์เฟซที่เปิดเผยมุมมองแบบแถวหรือแบบคอลัมน์ คุณสามารถใช้วัตถุลูกด้วยวิธีการเช่นvolumeและmoveซึ่งเพียงแก้ไขค่าตามลำดับในโครงสร้างคอลัมน์ฉลาดหลัก ในเวลาเดียวกันที่เก็บบอลของคุณสามารถเปิดเผยอินเทอร์เฟซสำหรับการดำเนินการคอลัมน์ฉลาด ด้วยเทมเพลต / ประเภทที่เหมาะสมและคอมไพเลอร์แบบอินไลน์ที่ฉลาดคุณสามารถใช้ abstractions เหล่านี้โดยไม่มีค่าใช้จ่ายในการใช้งานจริง

คุณจะเข้าถึงข้อมูลคอลัมน์ที่ชาญฉลาดบ่อยแค่ไหนกับการปรับเปลี่ยนข้อมูลแถวที่ชาญฉลาด? ในกรณีการใช้งานทั่วไปสำหรับการจัดเก็บคอลัมน์การเรียงลำดับของแถวจะไม่มีผลกระทบ คุณสามารถกำหนดการเรียงสับเปลี่ยนโดยพลการของแถวโดยการเพิ่มคอลัมน์ดัชนีแยก การเปลี่ยนการเรียงลำดับจะต้องการเพียงการสลับค่าในคอลัมน์ดัชนี

การเพิ่ม / กำจัดองค์ประกอบอย่างมีประสิทธิภาพสามารถทำได้ด้วยเทคนิคอื่น ๆ :

  • บำรุงรักษาบิตแมปของแถวที่ถูกลบแทนที่จะเปลี่ยนองค์ประกอบ กระชับโครงสร้างเมื่อเบาบางเกินไป
  • จัดกลุ่มแถวเป็นชิ้นขนาดที่เหมาะสมในโครงสร้างแบบ B-Tree เพื่อให้การแทรกหรือลบในตำแหน่งโดยพลการไม่จำเป็นต้องแก้ไขโครงสร้างทั้งหมด

รหัสลูกค้าจะเห็นลำดับของวัตถุ Ball, ภาชนะที่ไม่แน่นอนของวัตถุ Ball, ลำดับของรัศมี, เมทริกซ์ Nx3, ฯลฯ ; ไม่ต้องกังวลกับรายละเอียดที่น่าเกลียดของโครงสร้างที่ซับซ้อน (แต่มีประสิทธิภาพ) นั่นคือสิ่งที่วัตถุที่เป็นนามธรรมซื้อคุณ


1 AOS องค์กรเป็นอย่างดีทำให้ถูกต้องได้กับ API นิติบุคคลที่มุ่งเน้นความสุขถึงแม้ว่ามันจะกลายเป็นที่ยอมรับไม่สวยงามเท่าที่จะใช้ ( ball->do_something();เมื่อเทียบกับball_table.do_something(ball)) (&ball_table, index)ถ้าคุณต้องการที่จะปลอมเป็นนิติบุคคลที่เชื่อมโยงกันผ่านทางหลอกตัวชี้

1
ฉันจะไปอีกขั้น: ข้อสรุปในการใช้ SoA สามารถเข้าถึงได้อย่างหมดจดจากหลักการออกแบบ OO เคล็ดลับคือคุณต้องมีสถานการณ์ที่คอลัมน์เป็นวัตถุพื้นฐานมากกว่าแถว ลูกบอลไม่ใช่ตัวอย่างที่ดีที่นี่ ให้พิจารณาภูมิประเทศที่มีคุณสมบัติหลากหลายเช่นความสูงชนิดของดินหรือปริมาณน้ำฝนแทน แต่ละคุณสมบัติถูกสร้างแบบจำลองเป็นวัตถุ ScalarField ซึ่งมีวิธีการของตนเองเช่น gradient () หรือ divergence () ที่อาจส่งคืนวัตถุ Field อื่น ๆ คุณสามารถแค็ปซูลสิ่งต่าง ๆ เช่นความละเอียดของแผนที่และคุณสมบัติต่าง ๆ บนภูมิประเทศสามารถทำงานได้กับความละเอียดที่แตกต่างกัน
16807

4

คำตอบสั้น ๆ : คุณถูกต้องครบถ้วนและบทความเช่นนี้หายไปอย่างสมบูรณ์ประเด็นนี้

คำตอบแบบเต็มคือ: "โครงสร้างของอาร์เรย์" ตัวอย่างของคุณสามารถมีข้อได้เปรียบด้านประสิทธิภาพสำหรับการดำเนินงานบางประเภท ("การดำเนินงานคอลัมน์") และ "อาร์เรย์ของโครงสร้าง" สำหรับการดำเนินการประเภทอื่น ("การดำเนินงานแถว) "เช่นเดียวกับที่คุณกล่าวถึงข้างต้น) หลักการเดียวกันนี้มีอิทธิพลต่อสถาปัตยกรรมฐานข้อมูลมีฐานข้อมูลแบบคอลัมน์เทียบกับฐานข้อมูลแบบแถวแบบคลาสสิก

ดังนั้นสิ่งที่สองที่ควรพิจารณาในการเลือกการออกแบบคือการดำเนินการใดที่คุณต้องการมากที่สุดในโปรแกรมของคุณและถ้าสิ่งเหล่านั้นจะได้รับประโยชน์จากรูปแบบหน่วยความจำที่ต่างกัน อย่างไรก็ตามสิ่งแรกที่ต้องพิจารณาคือถ้าคุณต้องการประสิทธิภาพจริง ๆ(ฉันคิดว่าในการเขียนโปรแกรมเกมที่บทความข้างต้นมาจากคุณมักจะมีข้อกำหนดนี้)

ภาษา OO ปัจจุบันส่วนใหญ่ใช้โครงร่างหน่วยความจำ "Array-Of-Struct" สำหรับวัตถุและคลาส การได้รับข้อดีของ OO (เช่นการสร้าง abstractions สำหรับข้อมูลของคุณการห่อหุ้มและขอบเขตการทำงานพื้นฐานในท้องถิ่นมากขึ้น) มักจะเชื่อมโยงกับเค้าโครงหน่วยความจำชนิดนี้ ดังนั้นตราบใดที่คุณไม่ใช้คอมพิวเตอร์ประสิทธิภาพสูงฉันจะไม่ถือว่า SOA เป็นแนวทางหลัก


3
DOD ไม่ได้หมายถึงรูปแบบโครงสร้างของอาร์เรย์ (SoA) เสมอไป เป็นเรื่องปกติเพราะมันมักจะตรงกับรูปแบบการเข้าถึง แต่เมื่อเค้าโครงอื่นทำงานได้ดีขึ้นโดยทั้งหมดใช้มัน DOD นั้นกว้างกว่า (และคลุมเครือ) มากกว่าเป็นกระบวนทัศน์การออกแบบมากกว่าวิธีเฉพาะในการจัดวางข้อมูล นอกจากนี้ในขณะที่บทความที่คุณอ้างอิงอยู่ไกลจากแหล่งข้อมูลที่ดีที่สุดและมีข้อบกพร่องของมันก็ไม่ได้โฆษณารูปแบบ SoA "A" และ "B" สามารถเป็นคุณลักษณะที่สมบูรณ์Ballเช่นเดียวกับที่พวกเขาสามารถเป็นfloats หรือบุคคลvec3(ซึ่งตัวเองจะต้องอยู่ภายใต้การเปลี่ยนแปลง SOA)

2
... และการออกแบบที่เน้นแถวที่คุณพูดถึงนั้นรวมอยู่ใน DOD เสมอ มันเรียกว่าอาเรย์ของโครงสร้าง (AoS) และความแตกต่างกับสิ่งที่ทรัพยากรส่วนใหญ่เรียกว่า "วิธี OOP" (เพื่อดีกว่าหรือสูญเปล่า) ไม่ได้อยู่ในแถวเทียบกับการจัดวางคอลัมน์ เชื่อมโยงผ่านพอยน์เตอร์กับตารางต่อเนื่องขนาดใหญ่ของระเบียนทั้งหมด) โดยสรุป -1 เพราะแม้ว่าคุณจะได้คะแนนที่ดีจากการเข้าใจผิดของ OP แต่คุณได้แสดงแจ๊ส DOD ทั้งหมดแทนที่จะบิดเบือนความเข้าใจของ DOD

@delnan: ขอบคุณสำหรับความคิดเห็นของคุณคุณอาจถูกต้องที่ฉันควรจะใช้คำว่า "SoA" แทน "DOD" ฉันแก้ไขคำตอบของฉัน
Doc Brown

ดีกว่ามากลบคะแนนโหวตแล้ว ลองดูคำตอบของผู้ใช้ 2313838 สำหรับวิธีการรวม SOA ด้วย "object" - API ที่ดี (ในแง่ของ abstractions, encapsulation และ "ขอบเขตของฟังก์ชันพื้นฐาน") มันเป็นธรรมชาติมากขึ้นสำหรับรูปแบบ AoS (เนื่องจากอาร์เรย์สามารถเป็นคอนเทนเนอร์ทั่วไปที่เป็นใบ้ได้มากกว่าที่จะแต่งงานกับประเภทองค์ประกอบ) แต่เป็นไปได้

และgithub.com/BSVino/JaiPrimer/blob/master/JaiPrimer.mdซึ่งมีการแปลงอัตโนมัติจาก SOA เป็น / จาก AoS ตัวอย่าง: reddit.com/r/rust/comments/2t6xqz/ แล้วมีข่าวนี้อยู่ ycombinator.com/item?id=10235766
Jerry Jeremiah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.