ก่อนอื่นอย่าสับสนกับการออกแบบที่ขับเคลื่อนด้วยข้อมูล
ความเข้าใจของฉันเกี่ยวกับการออกแบบเชิงข้อมูลคือการจัดการข้อมูลของคุณเพื่อการประมวลผลที่มีประสิทธิภาพ โดยเฉพาะอย่างยิ่งเกี่ยวกับการแคชพลาดท่า ฯลฯ ข้อมูลขับเคลื่อนการออกแบบบนมืออื่น ๆ ที่เป็นเรื่องเกี่ยวกับการให้ข้อมูลการควบคุมจำนวนมากของโปรแกรมพฤติกรรมของคุณ (อธิบายได้เป็นอย่างดีโดยคำตอบของคี ธ แอนดรู )
สมมติว่าคุณมีลูกวัตถุในแอปพลิเคชันของคุณที่มีคุณสมบัติเช่นสีรัศมีวงเวียนตำแหน่ง ฯลฯ
วิธีการเชิงวัตถุ
ใน OOP คุณจะต้องอธิบายลูกบอลแบบนี้:
class Ball {
Point position;
Color color;
double radius;
void draw();
};
แล้วคุณจะสร้างคอลเลคชั่นของลูกบอลดังนี้:
vector<Ball> balls;
วิธีการที่มุ่งเน้นข้อมูล
อย่างไรก็ตามในการออกแบบที่เน้นข้อมูลคุณมีแนวโน้มที่จะเขียนโค้ดดังนี้:
class Balls {
vector<Point> position;
vector<Color> color;
vector<double> radius;
void draw();
};
อย่างที่คุณเห็นว่าไม่มีหน่วยเดียวที่แสดงถึงลูกบอลหนึ่งลูกอีกต่อไป วัตถุลูกมีอยู่โดยปริยายเท่านั้น
สิ่งนี้มีข้อดีหลายประการประสิทธิภาพที่ชาญฉลาด โดยปกติเราต้องการดำเนินการกับลูกบอลหลายลูกในเวลาเดียวกัน ฮาร์ดแวร์มักต้องการให้หน่วยความจำต่อเนื่องขนาดใหญ่ทำงานได้อย่างมีประสิทธิภาพ
ประการที่สองคุณอาจทำการดำเนินการที่มีผลต่อคุณสมบัติของลูกบอลบางส่วนเท่านั้น เช่นถ้าคุณรวมสีของลูกบอลทั้งหมดด้วยวิธีต่าง ๆ คุณต้องการให้แคชของคุณมีเฉพาะข้อมูลสี อย่างไรก็ตามเมื่อคุณสมบัติลูกทั้งหมดถูกเก็บไว้ในหน่วยเดียวคุณจะดึงคุณสมบัติอื่น ๆ ของลูกบอลด้วย แม้ว่าคุณไม่ต้องการพวกเขา
ตัวอย่างการใช้แคช
สมมติว่าลูกบอลแต่ละลูกใช้เวลา 64 ไบต์และคะแนนจะใช้เวลา 4 ไบต์ ช่องแคชใช้เวลาพูด 64 ไบต์เช่นกัน ถ้าฉันต้องการอัปเดตตำแหน่งของ 10 ลูกฉันต้องดึงหน่วยความจำ 10 * 64 = 640 ไบต์ในแคชและรับ 10 แคช หาก แต่ฉันสามารถทำงานในตำแหน่งของลูกบอลเป็นหน่วยแยกได้นั่นจะใช้เวลา 4 * 10 = 40 ไบต์เท่านั้น เหมาะกับการดึงข้อมูลแคชครั้งเดียว ดังนั้นเราจะได้รับเพียงแค่ 1 แคชเพื่ออัพเดทลูกบอลทั้งหมด 10 ลูก ตัวเลขเหล่านี้โดยพลการ - ฉันถือว่าบล็อกแคชใหญ่กว่า
แต่มันแสดงให้เห็นว่าเลย์เอาต์ของหน่วยความจำสามารถมีผลกระทบอย่างรุนแรงต่อความนิยมแคชและประสิทธิภาพได้อย่างไร สิ่งนี้จะเพิ่มความสำคัญเมื่อความแตกต่างระหว่างความเร็ว CPU และ RAM กว้างขึ้น
วิธีการจัดวางหน่วยความจำ
ในตัวอย่างบอลของฉันฉันทำให้ปัญหาง่ายขึ้นมากเพราะโดยปกติแล้วสำหรับแอปทั่วไปคุณจะเข้าถึงตัวแปรหลายตัวพร้อมกันได้ ตำแหน่งและรัศมีเช่นอาจจะใช้ร่วมกันบ่อยครั้ง โครงสร้างของคุณควรเป็น:
class Body {
Point position;
double radius;
};
class Balls {
vector<Body> bodies;
vector<Color> color;
void draw();
};
เหตุผลที่คุณควรทำเช่นนี้คือถ้าข้อมูลที่ใช้ร่วมกันถูกวางไว้ในอาร์เรย์ที่แยกต่างหากมีความเสี่ยงที่จะแข่งขันกันสำหรับสล็อตเดียวกันในแคช ดังนั้นการโหลดหนึ่งจะโยนอื่น ๆ
ดังนั้นเมื่อเทียบกับการเขียนโปรแกรม Object Oriented คลาสที่คุณทำไม่เกี่ยวข้องกับเอนทิตีในแบบจำลองทางจิตของปัญหา เนื่องจากข้อมูลถูกรวมเข้าด้วยกันตามการใช้ข้อมูลคุณจึงไม่มีชื่อที่สมเหตุสมผลในการให้ชั้นเรียนของคุณใน Data Oriented Design
ความสัมพันธ์กับฐานข้อมูลเชิงสัมพันธ์
การคิดที่อยู่เบื้องหลัง Data Oriented Design นั้นคล้ายคลึงกับวิธีคิดของคุณเกี่ยวกับฐานข้อมูลเชิงสัมพันธ์ การปรับฐานข้อมูลเชิงสัมพันธ์ให้เหมาะสมยังสามารถเกี่ยวข้องกับการใช้แคชได้อย่างมีประสิทธิภาพมากขึ้นแม้ว่าในกรณีนี้แคชไม่ใช่ CPU แคช แต่เป็นหน้าในหน่วยความจำ นักออกแบบฐานข้อมูลที่ดียังมีแนวโน้มที่จะแยกข้อมูลที่เข้าถึงไม่บ่อยออกเป็นตารางแยกต่างหากแทนที่จะสร้างตารางที่มีคอลัมน์จำนวนมากมีเพียงไม่กี่คอลัมน์เท่านั้นที่เคยใช้ เขาอาจเลือกที่จะทำให้บางส่วนของตารางเป็นปกติเพื่อไม่ให้เข้าถึงข้อมูลจากหลายตำแหน่งบนดิสก์ เช่นเดียวกับ Data Oriented Design ตัวเลือกเหล่านี้ถูกสร้างขึ้นโดยการดูว่ารูปแบบการเข้าถึงข้อมูลคืออะไรและจุดอ่อนของประสิทธิภาพการทำงานที่ใด