การออกแบบเชิงข้อมูลคืออะไร


156

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

ฉัน googled นี้และไม่สามารถหาข้อมูลจริงใด ๆ เกี่ยวกับสิ่งนี้คือให้ตัวอย่างรหัสใด ๆ มีใครบ้างที่คุ้นเคยกับคำนี้และสามารถเป็นตัวอย่างได้หรือไม่? นี่อาจเป็นคำอื่นสำหรับสิ่งอื่นหรือไม่?


7
บทความว่าในนักพัฒนาเกมอยู่ในขณะนี้ในง่ายต่อการอ่านในรูปแบบบล็อก: gamesfromwithin.com/data-oriented-design
Edmundito

58
พวกคุณเคยทำอะไรซักอย่างหรือไม่พบคำถาม SO ที่ตรงเป้าหมายและจากนั้นก็รู้ว่าคุณเป็นคนถามเมื่อหลายปีก่อน?
ryeguy


14
@ryeguy ฉันมีคำถาม googled พบคำถาม SO ที่ดีและจากนั้นก็ตระหนักว่าฉันตอบไปหลายปีแล้ว
Michael Deardeuff

4
ฉัน Googled บางสิ่งบางอย่างและพบคำถาม SO ที่ดีและเดาอะไร มันไม่ได้ฉันไม่ถามว่าใครที่มิได้ตอบ :)
Nadjib Mami

คำตอบ:


289

ก่อนอื่นอย่าสับสนกับการออกแบบที่ขับเคลื่อนด้วยข้อมูล

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

สมมติว่าคุณมีลูกวัตถุในแอปพลิเคชันของคุณที่มีคุณสมบัติเช่นสีรัศมีวงเวียนตำแหน่ง ฯลฯ

วิธีการเชิงวัตถุ

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


4
ขอบคุณสำหรับสิ่งนี้คุณอธิบายได้ดีมาก
ryeguy

4
พูดได้ดี; ฉันมีคำถามเดียวเท่านั้น สมมติว่าเรามีโครงสร้างstruct balls {vector<vec3> pos; vector<vec3> velocity;}จะไม่อัปเดตตำแหน่งของลูกบอลแต่ละอันที่จริงจะฟาดแคชเพราะคุณจะย้ายไปมาระหว่างเวกเตอร์ความเร็วและเวกเตอร์ตำแหน่ง (ใช่เครื่องจักรที่ทันสมัยและแคชไลน์และทั้งหมดนี้คือ ยังเป็นเพียงภาพประกอบ)
falstro

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

1
@roe คุณควรจัดกลุ่มคุณสมบัติเข้าด้วยกันซึ่งเข้าถึงได้ด้วยกัน ระหว่างคุณสมบัติไม่ควรมีการพึ่งพาใด ๆ เลย struct balls { vector<color> colors; vector<body> bodies; /* contains position and velocity */ }ดังนั้นโครงสร้างนี้จะดีกว่า
danijar

2
@danijar ฉันอัปเดตคำอธิบายพร้อมกับคำแนะนำของคุณ ฉันพูดได้มากกว่านี้เกี่ยวกับเรื่องนี้ แต่มันจะกลายเป็นบทความจริงๆ
Erik Engheim

18

Mike Acton ได้พูดคุยเกี่ยวกับการออกแบบเชิงข้อมูลเมื่อเร็ว ๆ นี้:

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

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


14

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


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

-3

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

วิธีการขั้นตอน

int animation; // this value is the animation index

if(animation == 0)
   PerformMoveForward();
else if(animation == 1)
  PerformMoveBack();
.... // etc

แนวทางการออกแบบข้อมูล

typedef struct
{
   int Index;
   void (*Perform)();
}AnimationIndice;

// build my animation dictionary
AnimationIndice AnimationIndices[] = 
  {
      { 0,PerformMoveForward }
      { 1,PerformMoveBack }
  }

// when its time to run, i use my dictionary to find my logic
int animation; // this value is the animation index
AnimationIndices[animation].Perform();

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


14
สิ่งนี้ไม่ถูกต้อง คุณกำลังสับสนการออกแบบเชิงข้อมูลด้วยการออกแบบที่ขับเคลื่อนด้วยข้อมูล ฉันทำสิ่งเดียวกันจนกว่าฉันจะอ่านบทความของโนเอลและตระหนักว่าเขากำลังพูดถึงสิ่งที่แตกต่างอย่างสิ้นเชิง
Erik Engheim

12
นอกจากนี้ Indice ไม่ใช่คำพูด มี "ดัชนี" และ "ดัชนี" และบางคนถึงกับยอม "ดัชนี" แต่ "ดัชนี" ไม่ถูกต้อง
Baxissimo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.