Що таке дизайн, орієнтований на дані?


156

Я читав цю статтю , і цей хлопець продовжує говорити про те, як кожен може отримати велику користь від змішування дизайну, орієнтованого на дані, з OOP. Однак він не показує зразків коду.

Я переглянув це і не зміг знайти реальну інформацію про те, що це таке, не кажучи вже про будь-які зразки коду. Хтось знайомий з цим терміном і може навести приклад? Це, можливо, інше слово для чогось іншого?


7
Ця стаття в розробнику ігор тепер доступна у легкій формі для читання у формі блогу: gamesfromwithin.com/data-oriented-design
Edmundito

58
Ви, хлопці, коли-небудь щось гуглили, знайшли приємне цілеспрямоване запитання, а потім зрозуміли, що саме ви його задавали роки тому?
ryeguy

1
Ось
агрегат

14
@ryeguy, у мене виникло запитання, погуглили його, знайшли приємне питання SO, а потім зрозуміли, що я відповів на нього років тому.
Майкл Дірдеуфф

4
Я щось погукав і знайшов приємне питання ТА здогадуюсь що? Це я не запитав, а не хто відповів :)
Наджіб Мамі

Відповіді:


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 балів. Ці числа довільні - я припускаю, що кеш-блок більший.

Але це ілюструє, як компонування пам'яті може мати серйозний вплив на хіти кешу і, таким чином, на продуктивність. Це збільшуватиметься лише у міру збільшення різниці між швидкістю процесора та оперативної пам’яті.

Як розташувати пам'ять

У своєму прикладі балу я багато спростив проблему, тому що зазвичай для будь-якого звичайного додатка ви, швидше за все, отримаєте доступ до кількох змінних разом. Наприклад, положення та радіус, ймовірно, часто використовуються разом. Тоді ваша структура повинна бути:

class Body {
  Point  position;
  double radius;
};

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

  void draw();
};

Причина, з якої ви повинні це зробити, полягає в тому, що якщо дані, що використовуються разом, розміщуються в окремих масивах, є ризик, що вони будуть конкурувати за ті самі слоти в кеші. Таким чином, завантаження одного викине іншого.

Отже, порівняно з об'єктно-орієнтованим програмуванням, класи, які ви закінчуєте створювати, не пов'язані з сутністю вашої ментальної моделі проблеми. Оскільки дані збираються разом на основі використання даних, ви не завжди матимете розумних імен, щоб давати свої класи в дизайні, орієнтованому на дані.

Ставлення до реляційних баз даних

Мислення, орієнтоване на дизайн, орієнтований на дані, дуже схоже на те, як ви думаєте про реляційні бази даних. Оптимізація реляційної бази даних також може залучати ефективніше використовувати кеш, хоча в цьому випадку кеш - це не кеш процесора, а сторінки в пам'яті. Хороший дизайнер баз даних також, швидше за все, розділяє нечасто доступні дані в окрему таблицю, а не створює таблицю з величезною кількістю стовпців, коли колись використовуються лише кілька стовпців. Він також може вирішити денормалізувати деякі таблиці, щоб дані не мали доступу з кількох місць на диску. Як і в дизайні, орієнтованому на дані, ці варіанти робляться, дивлячись, які бувають схеми доступу до даних та де вузьке місце продуктивності.


4
Дякую за це, ви дуже добре це пояснили.
ржигуй

4
добре сказано; Однак у мене є лише одне питання. Скажімо, у нас є структура struct balls {vector<vec3> pos; vector<vec3> velocity;}, яка б не оновлювала положення кожної кулі, насправді розбиває кеш, оскільки ви рухаєтеся вперед-назад між вектором швидкості та вектором позиції (так, сучасні машини та кеш-лінії та все таке, це також просто ілюстрація)?
falstro

14
Це могло б. Але пам’ятайте, що весь масив pos не залучається за один раз. Всього один рядок кешу і можливе попереднє завантаження. Так само зі швидкістю. Тож для того, щоб вони перебирали один одного, кожен відповідний фрагмент pos і vector доводиться зіставляти в одній кеш-лінії. Це, звичайно, може статися, тому рекомендація полягає в тому, щоб змінні, які використовуються разом, в структурі. Так, наприклад, швидкість і пози були б в одному векторі, а колір - в іншому.
Ерік Енгхайм

1
@roe Ви повинні згрупувати властивості разом, до яких можна отримати доступ разом. Між властивостями взагалі не повинно бути залежностей. Тож ця структура була б кращою struct balls { vector<color> colors; vector<body> bodies; /* contains position and velocity */ }.
danijar

2
@danijar Я оновив пояснення з вашими пропозиціями. Я міг би сказати про це набагато більше, але це справді просто перетвориться на статтю.
Ерік Енгхайм

18

Нещодавно Майк Актон виступив з громадськістю про проект, орієнтований на дані :

Основним моїм підсумком цього було б: якщо ви хочете продуктивність, тоді подумайте про потік даних, знайдіть шар зберігання, який, швидше за все, зв'язаний з вами, і оптимізуйте для цього важко. Майк зосереджується на помилках кешу 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
Це насправді не правильно. Ви плутаєте дизайн, орієнтований на дані, та дизайн, керований даними. Я робив те саме, поки не прочитав статті Ноеля і не зрозумів, що він говорить про щось зовсім інше.
Ерік Енгхайм

12
Також Індіке - це не слово. Існують "індекси" та "індекси", а деякі навіть опрощають "індекси", але "індекси" ніколи не підходять.
Baxissimo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.