Прежде всего, не путайте это с дизайном, управляемым данными.
Я понимаю, что 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, этот выбор делается при рассмотрении шаблонов доступа к данным и узких мест производительности.