Thiết kế định hướng dữ liệu là gì?


156

Tôi đã đọc bài viết này , và anh chàng này tiếp tục nói về việc mọi người có thể hưởng lợi rất nhiều từ việc trộn lẫn trong thiết kế hướng dữ liệu với OOP. Anh ta không hiển thị bất kỳ mẫu mã, tuy nhiên.

Tôi đã hiểu được điều này và không thể tìm thấy bất kỳ thông tin thực sự nào về việc này là gì, chứ đừng nói đến bất kỳ mẫu mã nào. Có ai quen thuộc với thuật ngữ này và có thể cung cấp một ví dụ? Đây có lẽ là một từ khác cho một cái gì đó khác?


7
Bài viết đó trong Nhà phát triển trò chơi hiện có sẵn dễ đọc ở dạng blog: gamesfromwithin.com/data-oriented-design
Edmundito

58
Các bạn đã bao giờ googled một cái gì đó, tìm thấy một câu hỏi SO nhắm mục tiêu tốt đẹp, và sau đó nhận ra đó là bạn đã hỏi nó nhiều năm trước?
ryeguy

1
Đây là một tổng hợp nội dung DOD trên web
legends2k

14
@ryeguy, tôi đã có một câu hỏi, googled nó, tìm thấy một câu hỏi SO hay, và sau đó nhận ra rằng tôi đã trả lời nó nhiều năm trước.
Michael Deardeuff

4
Tôi đã googled một cái gì đó và tìm thấy một câu hỏi SO đẹp và đoán những gì? Không phải tôi hỏi ai cũng không trả lời :)
Nadjib Mami

Câu trả lời:


287

Trước hết, đừng nhầm lẫn điều này với thiết kế hướng dữ liệu.

Sự hiểu biết của tôi về Thiết kế hướng dữ liệu là về việc tổ chức dữ liệu của bạn để xử lý hiệu quả. Đặc biệt là liên quan đến các lỗi nhớ cache, v.v. Mặt khác, Data Driven Design là về việc cho phép dữ liệu kiểm soát nhiều hành vi chương trình của bạn (được mô tả rất tốt theo câu trả lời của Andrew Keith ).

Giả sử bạn có các đối tượng bóng trong ứng dụng của mình với các thuộc tính như màu sắc, bán kính, độ nảy, vị trí, v.v.

Phương pháp hướng đối tượng

Trong OOP bạn sẽ mô tả các quả bóng như thế này:

class Ball {
  Point  position;
  Color  color;
  double radius;

  void draw();
};

Và sau đó bạn sẽ tạo ra một bộ sưu tập các quả bóng như thế này:

vector<Ball> balls;

Phương pháp định hướng dữ liệu

Tuy nhiên, trong Thiết kế hướng dữ liệu, bạn có nhiều khả năng viết mã như thế này:

class Balls {
  vector<Point>  position;
  vector<Color>  color;
  vector<double> radius;

  void draw();
};

Như bạn có thể thấy không còn đơn vị nào đại diện cho một Quả bóng nữa. Đối tượng bóng chỉ tồn tại ngầm.

Điều này có thể có nhiều lợi thế, hiệu suất khôn ngoan. Thông thường chúng tôi muốn thực hiện các hoạt động trên nhiều quả bóng cùng một lúc. Phần cứng thường muốn khối bộ nhớ lớn liên tục hoạt động hiệu quả.

Thứ hai, bạn có thể thực hiện các hoạt động chỉ ảnh hưởng đến một phần của các thuộc tính bóng. Ví dụ: nếu bạn kết hợp màu sắc của tất cả các quả bóng theo nhiều cách khác nhau, thì bạn muốn bộ đệm của bạn chỉ chứa thông tin màu. Tuy nhiên, khi tất cả các thuộc tính bóng được lưu trữ trong một đơn vị, bạn cũng sẽ kéo theo tất cả các thuộc tính khác của một quả bóng. Mặc dù bạn không cần chúng.

Ví dụ sử dụng bộ nhớ cache

Giả sử mỗi quả bóng chiếm 64 byte và một Điểm mất 4 byte. Một khe bộ nhớ cũng mất 64 byte. Nếu tôi muốn cập nhật vị trí của 10 quả bóng, tôi phải kéo 10 * 64 = 640 byte bộ nhớ vào bộ đệm và nhận 10 lỗi bộ nhớ cache. Tuy nhiên, nếu tôi có thể làm việc các vị trí của các quả bóng dưới dạng các đơn vị riêng biệt, điều đó sẽ chỉ mất 4 * 10 = 40 byte. Điều đó phù hợp với một lần tìm nạp bộ đệm. Do đó, chúng tôi chỉ nhận được 1 lỗi nhớ cache để cập nhật tất cả 10 quả bóng. Những con số này là tùy ý - Tôi giả sử một khối bộ đệm lớn hơn.

Nhưng nó minh họa cách bố trí bộ nhớ có thể ảnh hưởng nghiêm trọng đến các lần truy cập bộ đệm và do đó hiệu suất. Điều này sẽ chỉ tăng tầm quan trọng khi sự khác biệt giữa tốc độ CPU và RAM mở rộng.

Cách bố trí bộ nhớ

Trong ví dụ bóng của tôi, tôi đã đơn giản hóa vấn đề rất nhiều, bởi vì thông thường đối với bất kỳ ứng dụng thông thường nào, bạn có thể sẽ truy cập nhiều biến số cùng nhau. Ví dụ: vị trí và bán kính có thể sẽ được sử dụng cùng nhau thường xuyên. Sau đó, cấu trúc của bạn sẽ là:

class Body {
  Point  position;
  double radius;
};

class Balls {
  vector<Body>  bodies;
  vector<Color>  color;

  void draw();
};

Lý do bạn nên làm điều này là nếu dữ liệu được sử dụng cùng nhau được đặt trong các mảng riêng biệt, có nguy cơ chúng sẽ cạnh tranh cho cùng một vị trí trong bộ đệm. Như vậy tải cái này sẽ vứt cái kia.

Vì vậy, so với lập trình hướng đối tượng, các lớp bạn kết thúc không liên quan đến các thực thể trong mô hình tinh thần của vấn đề. Vì dữ liệu được gộp lại với nhau dựa trên việc sử dụng dữ liệu, bạn sẽ không luôn có tên hợp lý để đặt các lớp của mình trong Thiết kế hướng dữ liệu.

Liên quan đến cơ sở dữ liệu quan hệ

Suy nghĩ đằng sau Thiết kế hướng dữ liệu rất giống với cách bạn nghĩ về cơ sở dữ liệu quan hệ. Tối ưu hóa cơ sở dữ liệu quan hệ cũng có thể liên quan đến việc sử dụng bộ đệm hiệu quả hơn, mặc dù trong trường hợp này, bộ đệm không phải là bộ đệm CPU mà là các trang trong bộ nhớ. Một nhà thiết kế cơ sở dữ liệu tốt cũng có thể sẽ phân tách dữ liệu được truy cập không thường xuyên vào một bảng riêng thay vì tạo một bảng có số lượng cột lớn chỉ một vài trong số các cột được sử dụng. Anh ta cũng có thể chọn không chuẩn hóa một số bảng để dữ liệu không phải được truy cập từ nhiều vị trí trên đĩa. Giống như với Thiết kế hướng dữ liệu, các lựa chọn này được thực hiện bằng cách xem xét các mẫu truy cập dữ liệu là gì và nơi tắc nghẽn hiệu suất.


4
Cảm ơn vì điều này, bạn đã giải thích nó rất tốt.
ryeguy

4
nói hay lắm; Tôi chỉ có một câu hỏi. Giả sử chúng ta có một cấu trúc struct balls {vector<vec3> pos; vector<vec3> velocity;}, sẽ không cập nhật vị trí của từng quả bóng thực sự phá vỡ bộ đệm vì bạn di chuyển qua lại giữa vectơ vận tốc và vectơ vị trí (vâng, các máy hiện đại và các dòng bộ đệm và tất cả điều đó, đây là cũng chỉ là một minh họa)?
falstro

14
Nó có thể. Nhưng hãy nhớ rằng toàn bộ mảng pos sẽ không được kéo vào cùng một lúc. Chỉ cần một dòng bộ đệm và có thể tìm nạp trước. Tương tự như vậy với vận tốc. Vì vậy, để chúng rác lẫn nhau từng đoạn tương ứng của pos và vector phải ánh xạ tới cùng một dòng. Điều đó tất nhiên có thể xảy ra, đó là lý do tại sao khuyến nghị là đặt các biến được sử dụng cùng nhau trong một cấu trúc. Vì vậy, ví dụ vận tốc và pos sẽ ở trong một vectơ trong khi màu sẽ ở một vectơ khác.
Erik Engheim

1
@roe Bạn nên nhóm các thuộc tính với nhau, được truy cập cùng nhau. Giữa các tài sản không nên có sự phụ thuộc nào cả. Vì vậy, cấu trúc này sẽ tốt hơn struct balls { vector<color> colors; vector<body> bodies; /* contains position and velocity */ }.
danijar

2
@danijar Tôi cập nhật lời giải thích với đề xuất của bạn. Tôi có thể nói nhiều hơn về điều này, nhưng điều đó thực sự sẽ biến thành một bài viết.
Erik Engheim

18

Mike Acton đã nói chuyện công khai về thiết kế theo định hướng Dữ liệu gần đây:

Tóm tắt cơ bản của tôi về nó sẽ là: nếu bạn muốn hiệu suất, sau đó suy nghĩ về luồng dữ liệu, hãy tìm lớp lưu trữ có khả năng bắt vít với bạn và tối ưu hóa cho nó một cách khó khăn. Mike đang tập trung vào bộ nhớ cache L2, vì anh ấy đang làm việc trong thời gian thực, nhưng tôi tưởng tượng điều tương tự áp dụng cho cơ sở dữ liệu (đọc đĩa) và thậm chí cả Web (yêu cầu HTTP). Đó là một cách hữu ích để làm lập trình hệ thống, tôi nghĩ vậy.

Lưu ý rằng nó không giúp bạn thoát khỏi suy nghĩ về thuật toán và độ phức tạp thời gian, nó chỉ tập trung sự chú ý của bạn vào việc tìm ra loại hoạt động đắt nhất mà sau đó bạn phải nhắm mục tiêu với các kỹ năng CS điên rồ của mình.


14

Tôi chỉ muốn chỉ ra rằng Noel đang nói cụ thể về một số nhu cầu cụ thể mà chúng ta phải đối mặt trong phát triển trò chơi. Tôi cho rằng các lĩnh vực khác đang thực hiện mô phỏng mềm thời gian thực sẽ được hưởng lợi từ việc này, nhưng không chắc là một kỹ thuật sẽ cho thấy sự cải thiện đáng chú ý đối với các ứng dụng kinh doanh nói chung. Thiết lập này là để đảm bảo rằng mọi bit hiệu suất cuối cùng được vắt ra khỏi phần cứng cơ bản.


Đã đồng ý. Một số lĩnh vực khác mà thiết kế hướng dữ liệu là đáng kể là: phần cứng và phần sụn cho các thiết bị băng thông cao (ví dụ: mạng hoặc lưu trữ); điện toán khoa học quy mô lớn (ví dụ mô phỏng thời tiết, gấp protein), xử lý tín hiệu (ví dụ âm thanh, hình ảnh, video), nén dữ liệu. Những thứ này thuộc "Khoa học và Kỹ thuật tính toán" đôi khi được cung cấp như một chuyên ngành riêng biệt với Khoa học Máy tính điển hình hơn.
rwong

-3

Thiết kế hướng dữ liệu là một thiết kế trong đó logic của ứng dụng được xây dựng từ các tập dữ liệu, thay vì các thuật toán thủ tục. Ví dụ

cách tiếp cận thủ tục.

int animation; // this value is the animation index

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

phương pháp thiết kế dữ liệu

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();

Các thiết kế dữ liệu như thế này thúc đẩy việc sử dụng dữ liệu để xây dựng logic của ứng dụng. Dễ dàng quản lý hơn, đặc biệt là trong các trò chơi video có thể có hàng ngàn đường dẫn logic dựa trên hoạt hình hoặc một số yếu tố khác.


14
Điều này thực sự không chính xác. Bạn đang nhầm lẫn thiết kế định hướng dữ liệu với thiết kế hướng dữ liệu. Tôi đã làm điều tương tự cho đến khi tôi đọc bài viết của Noel và nhận ra anh ấy đang nói về một thứ hoàn toàn khác.
Erik Engheim

12
Ngoài ra, Indice không phải là một từ. Có "chỉ mục" và "chỉ số" và một số thậm chí bỏ qua "chỉ mục", nhưng "chỉ số" không bao giờ đúng.
Baxissimo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.