Что такое ориентированный на данные дизайн?


156

Я читал эту статью , и этот парень продолжает рассказывать о том, как каждый может получить большую выгоду от смешения в ориентированном на данные дизайне с ООП. Однако он не показывает никаких примеров кода.

Я погуглил это и не смог найти никакой реальной информации о том, что это такое, не говоря уже о примерах кода. Кто-нибудь знаком с этим термином и может привести пример? Это может быть другое слово для чего-то другого?


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

58
Ребята, вы когда-нибудь что-нибудь гуглили, нашли хороший целевой вопрос, а потом поняли, что это вы задали это много лет назад?
Ryeguy


14
@ryeguy, у меня был вопрос, погуглил, нашел хороший вопрос, а потом понял, что ответил на него много лет назад.
Майкл Дирдеуфф

4
Я что-то гуглил и нашел хороший вопрос, и знаете что? Это не я ни тот, кто спросил, ни кто ответил :)
Наджиб Мами

Ответы:


289

Прежде всего, не путайте это с дизайном, управляемым данными.

Я понимаю, что Data Oriented Design - это организация ваших данных для эффективной обработки. Особенно в отношении пропусков кэша и т. Д. С другой стороны, Data Driven Design - это то, что позволяет данным контролировать поведение многих ваших программ (очень хорошо описано в ответе Эндрю Кейта ).

Допустим, в вашем приложении есть объекты-шарики со свойствами, такими как цвет, радиус, упругость, положение и т. Д.

Объектно-ориентированный подход

В ООП вы бы описали шары следующим образом:

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

  void draw();
};

И тогда вы создадите коллекцию шаров, как это:

vector<Ball> balls;

Ориентированный на данные подход

Однако в Data Oriented Design вы с большей вероятностью напишите такой код:

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

Причина, по которой вам следует это сделать, заключается в том, что если данные, используемые вместе, помещаются в отдельные массивы, существует риск, что они будут конкурировать за одни и те же слоты в кэше. Таким образом, загрузка одного выбросит другого.

Таким образом, по сравнению с объектно-ориентированным программированием, классы, которые вы в итоге делаете, не связаны с сущностями в вашей ментальной модели проблемы. Поскольку данные объединяются в единое целое на основе использования данных, у вас не всегда будут разумные имена для ваших классов в Data Oriented Design.

Отношение к реляционным базам данных

Концепция Data Oriented Design очень похожа на то, как вы думаете о реляционных базах данных. Оптимизация реляционной базы данных может также включать более эффективное использование кеша, хотя в этом случае кеш - это не кеш процессора, а страницы в памяти. Хороший конструктор баз данных, скорее всего, также разделит редко используемые данные на отдельные таблицы, а не создаст таблицу с огромным количеством столбцов, в которых когда-либо использовались только несколько столбцов. Он также может выбрать денормализацию некоторых таблиц, чтобы к данным не приходилось обращаться из нескольких мест на диске. Как и в случае с Data-Oriented Design, этот выбор делается при рассмотрении того, что такое шаблоны доступа к данным и где узкое место в производительности.


4
Спасибо за это, вы объяснили это очень хорошо.
ryeguy

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 */ }.
Данияр

2
@danijar Я обновил объяснение с вашими предложениями. Я мог бы сказать намного больше об этом, но это действительно просто превратится в статью.
Эрик Энгхайм,

18

Майк Актон недавно выступил с публичной речью о Дата-ориентированном дизайне :

Я подытожу это следующим образом: если вы хотите повысить производительность, подумайте о потоке данных, найдите уровень хранилища, который, скорее всего, вам не по душе, и оптимизируйте его под себя . Майк сосредотачивается на промахах кэша второго уровня, потому что он работает в режиме реального времени, но я думаю, что то же самое относится и к базам данных (чтение с диска) и даже к сети (запросы HTTP). Думаю, это полезный способ системного программирования.

Обратите внимание, что это не освобождает вас от размышлений об алгоритмах и сложности времени, а просто сосредотачивает ваше внимание на определении самого дорогого типа операций, на который вы затем должны нацелиться, используя свои безумные навыки CS.


14

Я просто хочу отметить, что Ноэль говорит конкретно о некоторых специфических потребностях, с которыми мы сталкиваемся при разработке игр. Я полагаю, что другие сектора, которые выполняют мягкое моделирование в реальном времени, выиграют от этого, но вряд ли это будет метод, который покажет заметное улучшение для общих бизнес-приложений. Эта настройка предназначена для обеспечения того, чтобы каждый последний бит производительности выдавливался из базового оборудования.


Согласовано. Некоторые другие области, в которых ориентирован на данные, имеют большое значение: аппаратное и программное обеспечение для устройств с высокой пропускной способностью (например, для сетей или хранилищ); крупномасштабные научные вычисления (например, моделирование погоды, сворачивание белков), обработка сигналов (например, аудио, изображения, видео), сжатие данных. Они подпадают под "вычислительную науку и инженерию", которая иногда предлагается в качестве отдельной специальности от более типичной информатики.
Рулон

-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
Также Indice это не слово. Есть «index» и «indexes» и некоторые даже оправдывают «indexes», но «indice» никогда не бывает правильным.
Baxissimo
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.